HDU - 4747 Mex
题意:对于每一段连续区间找到mex的值(mex 即为没出现过的数的最小非负数),然后对所有的改值进行求和, 输出ans。
题解:首先我门可以暴力的跑出 区间 [1,2], [1,3],……,[1,i]的mex值, 由于mex的定义, 我们可以得知, 左边的区间mex一定是不大于右边的区间的mex值, 然后可以通过线段树求和, 来访问这些值的和。 然后查询完一次数据之后, 我们将删除第一个数, 并且判断在[l+1,r-1](l为被删数出现的位置, r为下一个该数出现的位置) 的区间内是否有mex值大于该删除的值, 如果有就更新这一段区间的值, 用线段树加速更新操作,最后删完所有的点所统计的和就是答案了。
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define max3(a,b,c) max(a,max(b,c)) 12 #define min3(a,b,c) min(a,min(b,c)) 13 typedef pair<int,int> pll; 14 const int INF = 0x3f3f3f3f; 15 const LL mod = 1e9+7; 16 const int N = 2e5+10; 17 LL Max[N<<2], sum[N<<2], lazy[N<<2]; 18 int a[N], mex[N]; 19 void PushUp(int rt){ 20 sum[rt] = sum[rt<<1] + sum[rt<<1|1]; 21 Max[rt] = max(Max[rt<<1|1], Max[rt<<1]); 22 } 23 void PushDown(int rt, int llen, int rlen){ 24 if(lazy[rt] != -1){ 25 lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt]; 26 sum[rt<<1] = lazy[rt]*llen; 27 sum[rt<<1|1] = lazy[rt]*rlen; 28 Max[rt<<1] = Max[rt<<1|1] = lazy[rt]; 29 lazy[rt] = -1; 30 } 31 } 32 void Build(int l, int r, int rt){ 33 lazy[rt] = -1; 34 if(l == r) { 35 Max[rt] = sum[rt] = mex[l]; 36 return ; 37 } 38 int m = l+r >> 1; 39 Build(lson); 40 Build(rson); 41 PushUp(rt); 42 } 43 void Update(int l, int r, int rt, int L, int R, int c){ 44 if(L <= l && r <= R){ 45 Max[rt] = lazy[rt] = c; 46 sum[rt] = 1ll * (r-l+1) * c; 47 return ; 48 } 49 int m = l+r >> 1; 50 PushDown(rt, m-l+1, r-m); 51 if(L <= m) Update(lson, L, R, c); 52 if(m < R) Update(rson, L, R, c); 53 PushUp(rt); 54 } 55 LL Query(int l, int r, int rt, int L, int R){ 56 if(L <= l && r <= R) return sum[rt]; 57 int m = l+r >> 1; 58 LL ret = 0; 59 PushDown(rt, m-l+1, r-m); 60 if(L <= m) ret += Query(lson, L, R); 61 if(m < R) ret += Query(rson, L, R); 62 return ret; 63 } 64 int id(int l, int r, int rt, int v){ 65 if(l == r) return l; 66 int m = l+r >> 1; 67 PushDown(rt, m-l+1, r-m); 68 if(Max[rt<<1] > v) return id(lson, v); 69 return id(rson, v); 70 } 71 map<int, int> mp; 72 int Next[N]; 73 int main(){ 74 ///Fopen; 75 int n; 76 while(~scanf("%d", &n), n){ 77 for(int i = 1; i <= n; i++) scanf("%d", &a[i]); 78 mp.clear(); 79 int tmp = 0; 80 for(int i = 1; i <= n; i++){ 81 mp[a[i]] = 1; 82 while(mp.count(tmp)) tmp++; 83 mex[i] = tmp; 84 } 85 86 mp.clear(); 87 for(int i = n; i >= 1; i--){ 88 if(!mp.count(a[i])) Next[i] = n + 1; 89 else Next[i] = mp[a[i]]; 90 mp[a[i]] = i; 91 } 92 Build(1,n,1); 93 LL ans = 0; 94 for(int i = 1; i <= n; i++){ 95 ans += sum[1]; 96 if(Max[1] > a[i]){ 97 int l = id(1,n,1,a[i]);//找到最左边的大于被删除数的位置,由mex的定义可知,后面的值一定也不小于这个节点 98 int r = Next[i]; 99 if(l < r) Update(1, n, 1, l, r-1, a[i]); 100 } 101 Update(1,n,1,i,i,0); 102 } 103 printf("%I64d\n", ans); 104 } 105 return 0; 106 }