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
",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
",ans);
81         }
82         printf("%lld
",ans);
83     }
84     return 0;
85 }
原文地址:https://www.cnblogs.com/DriverLao/p/9823066.html