感谢YB。
比赛的时候YY的做法,没写完。然后看别人的题解才知道是线段树,自己随手手写了一个,WA哭,然后去看别人写的,将线段树封装成结构体,这种写法牺牲一些空间(峰值一样),带来的是写法更清晰。线段树的题目也写不少了,但是还是不熟悉。
题意:mex(l,r)表示a[l]到a[r]中没出的最小非负数,然后求出所有合法区间的mex的和。
首先容易求出mex(1,i),i=1,2,3,...,n,然后从i开始推出i+1开始的mex的和,显然,mex的值是不下降的,当mex的值小于a[i]时,可以修改mex为a[i],每次找到第一个大于mex的值的位置,更新到下一个a[k]=a[i]的位置,就行了。
1 #include <stdio.h> 2 #include <string.h> 3 typedef long long ll; 4 const int maxn = 2e5 + 5; 5 int n, p, a[maxn], vis[maxn], npos[maxn]; 6 struct node { 7 ll sum; 8 int l, r, max, Lazy; 9 }tr[maxn << 2]; 10 #define lc o << 1 11 #define rc lc | 1 12 #define m ((t.l + t.r) >> 1) 13 inline int max(int x, int y) { return x > y ? x : y;} 14 inline void pushUp(int o) { 15 tr[o].sum = tr[lc].sum + tr[rc].sum; 16 tr[o].max = max(tr[lc].max, tr[rc].max); 17 } 18 inline void pushDown(int o) { 19 if (tr[o].Lazy == -1) return; 20 tr[lc].max = tr[rc].max = tr[lc].Lazy = tr[rc].Lazy = tr[o].Lazy; 21 tr[lc].sum = (ll)tr[o].Lazy * (tr[lc].r - tr[lc].l + 1); 22 tr[rc].sum = (ll)tr[o].Lazy * (tr[rc].r - tr[rc].l + 1); 23 tr[o].Lazy = -1; 24 } 25 inline void buildTree(int o, int l, int r) { 26 node &t = tr[o]; 27 t.l = l; 28 t.r = r; 29 t.Lazy = -1; 30 if (l == r) { 31 vis[a[t.l]] = 1; 32 while (vis[p]) ++p; 33 t.sum = t.max = p; 34 } else { 35 buildTree(lc, l, m); 36 buildTree(rc, m + 1, r); 37 pushUp(o); 38 } 39 } 40 inline void modify(int o, int l, int r, int v) { 41 node &t = tr[o]; 42 if (l <= t.l && t.r <= r) { 43 t.Lazy = t.max = v; 44 t.sum = (ll)v * (t.r - t.l + 1); 45 } else { 46 pushDown(o); 47 if (l <= m) 48 modify(lc, l, r, v); 49 if (m < r) 50 modify(rc, l, r, v); 51 pushUp(o); 52 } 53 } 54 inline int getPos(int o, int v) { 55 node &t = tr[o]; 56 if (t.max < v) return t.r + 1; 57 if (t.l == t.r) return t.l; 58 pushDown(o); 59 if (v <= tr[lc].max) return getPos(lc, v); 60 return getPos(rc, v); 61 } 62 int main() { 63 while (~scanf("%d", &n) && n) { 64 for (int i = 1; i <= n; ++i) { 65 scanf("%d", &a[i]); 66 vis[i] = n + 1; 67 if (a[i] > n) 68 a[i] = n + 1; 69 } 70 vis[0] = vis[n + 1] = n + 1; 71 for (int i = n; i; --i) { 72 npos[i] = vis[a[i]]; 73 vis[a[i]] = i; 74 } 75 memset(vis, 0, sizeof(vis)); 76 p = 0; 77 buildTree(1, 1, n); 78 ll ans = 0; 79 for (int i = 1; i <= n; ++i) { 80 ans += tr[1].sum; 81 modify(1, 1, i, 0); 82 if (a[i] >= tr[1].max) 83 continue; 84 int l = getPos(1, a[i]); 85 if (l < npos[i]) 86 modify(1, l, npos[i] - 1, a[i]); 87 } 88 printf("%I64d\n", ans); 89 } 90 return 0; 91 }