HDU 4747 Mex【线段树上二分+扫描线】
【题意概述】
一个区间的Mex为这个区间没有出现过的最小自然数,现在给你一个序列,要求求出所有区间的Mex的和。
【题解】
扫描线+线段树。
我们在线段树上维护从当前左端点开始的前缀Mex,显然从左到右Mex单调上升。
然后我们把区间左端点逐渐向右边移动,也就是扫描线是左端点。
我们可以发现每次移动的影响就是 [这个数的位置, 这个数下一次出现的位置) 这个区间内大于这个数的Mex全部变为这个数。
那么我们在线段树上二分出第一个大于等于Mex的位置,然后区间修改即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define LL long long 5 #define rg register 6 #define N 200010 7 #define ls (u<<1) 8 #define rs (u<<1|1) 9 #define mid ((a[u].l+a[u].r)>>1) 10 using namespace std; 11 int n,m,v[N],b[N],c[N],nxt[N],pos[N],mex[N]; 12 LL ans,u[N]; 13 struct tree{int l,r,nl,nr; LL sum; bool tag;}a[N<<2]; 14 inline int read(){ 15 int k=0,f=1; char c=getchar(); 16 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 17 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 18 return k*f; 19 } 20 void build(int u,int l,int r){ 21 a[u].l=l; a[u].r=r; a[u].tag=0; 22 if(l<r){ 23 build(ls,l,mid); build(rs,mid+1,r); 24 a[u].sum=a[ls].sum+a[rs].sum; a[u].nl=a[ls].nl,a[u].nr=a[rs].nr; 25 } 26 else a[u].sum=a[u].nl=a[u].nr=mex[l]; 27 } 28 inline void pushdown(int u){ 29 a[ls].tag=a[rs].tag=1; 30 a[ls].nl=a[ls].nr=a[rs].nl=a[rs].nr=a[u].nl; 31 a[ls].sum=(a[ls].r-a[ls].l+1)*a[ls].nl; 32 a[rs].sum=(a[rs].r-a[rs].l+1)*a[rs].nl; 33 a[u].tag=0; 34 } 35 void update(int u,int l,int r,int num){ 36 if(l<=a[u].l&&a[u].r<=r&&a[u].nl>num){ 37 a[u].tag=1; a[u].nl=a[u].nr=num; a[u].sum=(a[u].r-a[u].l+1)*num; 38 return; 39 } 40 if(a[u].nr<=num) return; 41 if(a[u].tag) pushdown(u); 42 if(a[ls].nr>num&&l<=mid) update(ls,l,r,num); 43 if(r>mid) update(rs,l,r,num); 44 a[u].sum=a[ls].sum+a[rs].sum; a[u].nl=a[ls].nl,a[u].nr=a[rs].nr; 45 } 46 LL query(int u,int l,int r){ 47 if(l<=a[u].l&&a[u].r<=r) return a[u].sum; 48 if(a[u].tag) pushdown(u); LL ret=0; 49 if(l<=mid) ret+=query(ls,l,r); 50 if(r>mid) ret+=query(rs,l,r); 51 return ret; 52 } 53 inline void Pre(){ 54 ans=0; 55 memset(pos,0,sizeof(pos)); 56 memset(u,0,sizeof(u)); 57 } 58 int main(){ 59 while(1){ 60 n=read(); if(!n) break; 61 Pre(); 62 for(rg int i=1;i<=n;i++) v[i]=b[i]=read(); 63 sort(b+1,b+1+n); m=unique(b+1,b+1+n)-b-1; 64 for(rg int i=1;i<=n;i++) c[i]=lower_bound(b+1,b+1+m,v[i])-b; 65 // for(rg int i=1;i<=n;i++) printf("%d ",c[i]); puts("c"); 66 for(rg int i=n;i;i--) nxt[i]=(pos[c[i]])?pos[c[i]]:n+1,pos[c[i]]=i; 67 // for(rg int i=1;i<=n;i++) printf("%d ",nxt[i]); puts(""); 68 int now=0; 69 for(rg int i=1;i<=n;i++){ 70 if(v[i]<=n) u[v[i]]=1; 71 while(u[now]) now++; 72 ans+=(mex[i]=now); 73 } 74 // for(rg int i=1;i<=n;i++) printf("%d ",mex[i]); 75 // printf("ans=%lld\n",ans); 76 build(1,1,n); 77 for(rg int i=1;i<=n;i++){ 78 update(1,i+1,nxt[i]-1,v[i]); 79 ans+=query(1,i+1,n); 80 // printf("ans=%lld\n",ans); 81 } 82 printf("%lld\n",ans); 83 } 84 return 0; 85 }