Mex(线段树的巧妙应用)
题目要求求某段区间第一个没有出现的数(0,1,2,3.。。。) ,对于所有的区间,我们把这样的数加起来最后得到一个结果。
首先,我们要求出这样的数,然后还得列举出所有的区间,复杂度太大了。
换种思路,我们定住L,是不是一次性能求出所有的R所得出的结果,这就用到线段树的性质了,因为在移动L的过程中,移一步只变化一个数,那么就可以用线段树进行维护。
首先求出[1,R] 以1为左端的所有区间的情况,记录每个点也就是1到那个点的这段区间值sum[i],以这个值建一颗树,那么在L向前移动的时候,每次丢掉一个数a[i-1], 因为少了这一个数,肯定后面有部分区间是变化的,有部分是不变化的,从这点开始向后找第一个与a[i-1]值相等的数的位置p,那么这个位置后面的sum肯定不会变化,因为丢掉的数又补上了。
那么就可以只考虑,从i位置到p这段里面的sum,如果原先的sum本来就比a[i-1]小,那说明a[i-1]的减少不影响它的值,所以不用改变,而所有大于a[i-1]的值将都变为a[i-1],这样更新一下,求和就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #include<cmath> 8 #include<queue> 9 #include<set> 10 #include<map> 11 using namespace std; 12 //#pragma comment(linker, "/STACK:1024000000,1024000000") 13 #define N 200010 14 #define LL __int64 15 #define INF 0xfffffff 16 const double eps = 1e-8; 17 const double pi = acos(-1.0); 18 const double inf = ~0u>>2; 19 vector<int>po[N]; 20 map<int,int>f; 21 LL s[N<<2]; 22 int tm[N<<2]; 23 LL lz[N<<2]; 24 int sum[N]; 25 int p[N],a[N]; 26 bool vis[N]; 27 void up(int w) 28 { 29 s[w] = s[w<<1]+s[w<<1|1]; 30 tm[w] = max(tm[w<<1],tm[w<<1|1]); 31 //cout<<tm[w]<<" "<<w<<endl; 32 } 33 void down(int w,int m) 34 { 35 if(lz[w]!=-1) 36 { 37 tm[w<<1] = tm[w<<1|1] = lz[w]; 38 lz[w<<1] = lz[w<<1|1] = lz[w]; 39 s[w<<1] = lz[w]*(m-m/2); 40 s[w<<1|1] = lz[w]*(m/2); 41 lz[w] = -1; 42 //cout<<lz[w]<<" <"<<w<<endl; 43 } 44 } 45 void build(int l,int r,int w) 46 { 47 if(l==r) 48 { 49 s[w] = sum[l]; 50 tm[w] = sum[l]; 51 return ; 52 } 53 int m = (l+r)>>1; 54 build(l,m,w<<1); 55 build(m+1,r,w<<1|1); 56 up(w); 57 } 58 void update(int a,int b,int d,int l,int r,int w) 59 { 60 if(a<=l&&b>=r) 61 { 62 s[w] = (LL)d*(r-l+1); 63 tm[w] = d; 64 lz[w] = d; 65 //cout<<l<<", "<<r<<" "<<tm[w]<<" "<<d<<endl; 66 return ; 67 } 68 int m = (l+r)>>1; 69 down(w,r-l+1); 70 if(a<=m) update(a,b,d,l,m,w<<1); 71 if(b>m) update(a,b,d,m+1,r,w<<1|1); 72 up(w); 73 } 74 int find(int k,int l,int r,int w) 75 { 76 // cout<<s[w]<<" "<<tm[w]<<" "<<l<<" "<<r<<" "<<w<<endl; 77 if(l==r) 78 { 79 //cout<<l<<" "<<tm[w]<<endl; 80 return l; 81 } 82 int m = (l+r)>>1; 83 down(w,r-l+1); 84 if(tm[w<<1]>k) 85 return find(k,l,m,w<<1); 86 else 87 return find(k,m+1,r,w<<1|1); 88 } 89 LL query(int a,int b,int l,int r,int w) 90 { 91 if(a<=l&&b>=r) 92 { 93 return s[w]; 94 } 95 int m = (l+r)>>1; 96 LL res = 0; 97 down(w,r-l+1); 98 if(a<=m) 99 res+=query(a,b,l,m,w<<1); 100 if(b>m) 101 res+=query(a,b,m+1,r,w<<1|1); 102 return res; 103 } 104 int main() 105 { 106 int n,i; 107 while(scanf("%d",&n)&&n) 108 { 109 f.clear(); 110 memset(p,0,sizeof(p)); 111 memset(vis,0,sizeof(vis)); 112 memset(lz,-1,sizeof(lz)); 113 for(i = 1; i <= n ; i++) 114 po[i].clear(); 115 int g = 0; 116 for(i = 1; i <= n; i++) 117 { 118 scanf("%d",&a[i]); 119 if(!f[a[i]]) f[a[i]] = ++g; 120 po[f[a[i]]].push_back(i); 121 } 122 int o = 0; 123 for(i = 1; i <= n ; i++) 124 { 125 if(a[i]<N) 126 vis[a[i]] = 1; 127 if(a[i]<sum[i-1]) 128 sum[i] = sum[i-1]; 129 else 130 { 131 while(vis[o]) 132 o++; 133 sum[i] = o; 134 } 135 } 136 LL ans=0; 137 build(1,n,1); 138 ans+=s[1]; 139 //cout<<ans<<endl; 140 p[f[a[1]]] = 1; 141 for(i = 2; i <= n ; i++) 142 { 143 int k; 144 int mk = f[a[i-1]]; 145 if(p[mk]<po[mk].size()) 146 { 147 k = po[mk][p[mk]]-1; 148 //cout<<k<<endl; 149 //p[mk]++; 150 } 151 else k = n; 152 update(1,i-1,0,1,n,1); 153 int fk; 154 if(tm[1]>a[i-1]) 155 { 156 fk = find(a[i-1],1,n,1); 157 update(fk,k,a[i-1],1,n,1); 158 } 159 ans+=query(i,n,1,n,1); 160 // cout<<ans<<endl; 161 //cout<<ans<<" "<<fk<<" "<<k<<" "<<a[i-1]<<endl; 162 //cout<<i<<endl; 163 //if(a[i]!=a[i-1]) 164 p[f[a[i]]]++; 165 } 166 cout<<ans<<endl; 167 } 168 return 0; 169 }