首先计算出以1为左端点的所有区间的mex,考虑删除左端点仍然维护这个序列:设当前删除点下一次出现在y,y~n的mex不变,从左端点到y的点中大于删除值的点要变成删除值,因为这个是不断递增的,所以是一段区间,可以用线段树来维护。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 200005 4 #define L (k<<1) 5 #define R (L+1) 6 #define mid (l+r>>1) 7 int n,a[N],fi[N],nex[N],laz[N<<2],ma[N<<2],vis[N]; 8 long long ans,f[N<<2]; 9 void update(int k,int l,int r,int x){ 10 laz[k]=ma[k]=x; 11 f[k]=x*(r-l+1); 12 } 13 void down(int k,int l,int r){ 14 if (laz[k]==-1)return; 15 update(L,l,mid,laz[k]); 16 update(R,mid+1,r,laz[k]); 17 laz[k]=-1; 18 } 19 void up(int k){ 20 f[k]=f[L]+f[R]; 21 ma[k]=max(ma[L],ma[R]); 22 } 23 void update(int k,int l,int r,int x,int y,int z){ 24 if ((l>y)||(x>r))return; 25 if ((x<=l)&&(r<=y)){ 26 update(k,l,r,z); 27 return; 28 } 29 down(k,l,r); 30 update(L,l,mid,x,y,z); 31 update(R,mid+1,r,x,y,z); 32 up(k); 33 } 34 int query(int k,int l,int r,int x){ 35 if (l==r)return l+(ma[k]<x); 36 down(k,l,r); 37 if (ma[L]>x)return query(L,l,mid,x); 38 return query(R,mid+1,r,x); 39 } 40 int main(){ 41 while (scanf("%d",&n)!=EOF){ 42 if (!n)return 0; 43 ans=0; 44 for(int i=1;i<=n;i++){ 45 scanf("%d",&a[i]); 46 if (a[i]>n)a[i]=n; 47 } 48 memset(vis,0,sizeof(vis)); 49 for(int i=0;i<=n;i++)fi[i]=n+1; 50 memset(laz,-1,sizeof(laz)); 51 for(int i=n;i;i--){ 52 nex[i]=fi[a[i]]; 53 fi[a[i]]=i; 54 } 55 for(int i=1,j=0;i<=n;i++){ 56 vis[a[i]]=1; 57 while (vis[j])j++; 58 update(1,1,n,i,i,j); 59 } 60 for(int i=1;i<n;i++){ 61 ans+=f[1]+i-1; 62 update(1,1,n,i,i,-1); 63 update(1,1,n,query(1,1,n,a[i]),nex[i]-1,a[i]); 64 } 65 printf("%lld\n",ans+(a[n]==0)); 66 } 67 }