HDU 4747 Mex 线段树 区间修改

感谢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 }
View Code

 

posted @ 2016-11-16 13:34  Apiec  阅读(411)  评论(0编辑  收藏  举报