[hdu4747]Mex

首先计算出以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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11382183.html