hdu 4747 (线段树)
题意:有一个序列a[],mex(L, R)表示区间a在区间[L, R]上第一个没出现的最小非负整数,对于序列a[],求所有的mex(L, R)的和(1 <= L <= R <= n,1 <= n <= 200000,0 <= ai <= 10^9)。
求出所有的mex(1, i);接着删去第1个结点,就是所有的mex(2, i);接着再删去第1个结点,就是所有的mex(3, i);……最后就是mex(n, n),求和即是答案。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 7 using namespace std; 8 #define ls rt<<1 9 #define rs rt<<1|1 10 #define lson l, m, rt<<1 11 #define rson m + 1, r, rt<<1|1 12 typedef long long ll; 13 const int maxn = 2e5 + 5; 14 int n, a[maxn], vis[maxn], next[maxn], mex1[maxn << 2]; 15 struct SegTree{ 16 int Max, lazy; 17 ll sum; 18 }seg[maxn << 2]; 19 20 void pushUp(int rt){ 21 seg[rt].sum = seg[ls].sum + seg[rs].sum; 22 seg[rt].Max = max(seg[ls].Max, seg[rs].Max); 23 } 24 void pushDown(int rt, int len){ 25 if (seg[rt].lazy != -1){ 26 seg[ls].lazy = seg[rs].lazy = seg[rt].lazy; 27 seg[ls].Max = seg[rt].lazy; 28 seg[rs].Max = seg[rt].lazy; 29 seg[ls].sum = (ll)((len + 1) / 2) * ((ll)seg[rt].lazy); 30 seg[rs].sum = (ll)(len / 2) * ((ll)seg[rt].lazy); 31 seg[rt].lazy = -1; 32 } 33 } 34 void build(int l, int r, int rt){ 35 seg[rt].lazy = -1; 36 if (l == r){ 37 seg[rt].sum = seg[rt].Max = mex1[l]; 38 return ; 39 } 40 int m = (l + r) >> 1; 41 build(lson); 42 build(rson); 43 pushUp(rt); 44 } 45 int find(int key, int l, int r, int rt){//找到第一个mex大于a[i]的下标 46 if (l == r) return l; 47 pushDown(rt, r - l + 1); 48 int m = (l + r) >> 1; 49 if (seg[ls].Max > key) return find(key, lson); 50 else return find(key, rson); 51 } 52 void update(int val, int L, int R, int l, int r, int rt){ 53 if (L <= l && r <= R){ 54 //pushDown(rt, r - l + 1); 55 seg[rt].Max = val; 56 seg[rt].sum = (ll) val * (ll) (r - l + 1); 57 seg[rt].lazy = val; 58 return ; 59 } 60 int m = (l + r) >> 1; 61 //cout << seg[rt].lazy << " l = " << l << " r= " << r << endl; 62 pushDown(rt, r - l + 1); 63 if (L <= m ) update(val, L, R, lson); 64 if (R > m) update(val, L, R, rson); 65 pushUp(rt); 66 /*if (L == 2 && R == 4){ 67 cout << " ll = " << l << " rr = " << r << endl; 68 cout << " sum = " << seg[rt].sum << " rt = " << rt << endl; 69 }*/ 70 } 71 int main(){ 72 while (~scanf("%d", &n) && n){ 73 for (int i = 1; i <= n; ++i){ 74 scanf("%d", &a[i]); 75 if (a[i] > n) a[i] = n; 76 } 77 //得到mex[1, i] 78 int tmp = 0; 79 memset(vis, 0, sizeof(vis)); 80 for (int i = 1; i <= n; ++i){ 81 vis[a[i]] = 1; 82 while(vis[tmp]) tmp++; 83 mex1[i] = tmp; 84 } 85 //得到next值 86 for (int i = 0; i <= n; ++i) vis[i] = n + 1; 87 for (int i = n; i >= 1; --i){ 88 next[i] = vis[a[i]]; 89 vis[a[i]] = i; 90 } 91 build(1, n, 1); 92 ll ans = 0; 93 for (int i = 1; i <= n; ++i){ 94 // cout << seg[1].sum << endl; 95 ans += seg[1].sum; 96 update(0, i, i, 1, n, 1); 97 if (a[i] < seg[1].Max){ 98 int l = find(a[i], 1, n, 1), r = next[i] - 1; 99 //cout << " l = " << l << " r = " << r << endl; 100 if (l <= r) update(a[i], l, r, 1, n, 1); 101 } 102 } 103 printf("%I64d\n", ans); 104 } 105 return 0; 106 }