线段树专题训练

模块一:

线段树单点更新,区间最值。

http://acm.hdu.edu.cn/showproblem.php?pid=1166

线段树功能:update:单点更新,query:区间求和。

http://acm.hdu.edu.cn/showproblem.php?pid=1754

 线段树功能:update:单点更新,query:区间最值。

PushUp(int rt) : 把当前节点的信息更新到父亲节点

PushDown(int rt) :  把父亲节点的信息更新到儿子节点。

 1 /*************************************************************************
 2     > File Name: hdu1754.cpp
 3     > Author: syhjh
 4     > Created Time: 2014年03月20日 星期四 21时52分56秒
 5  ************************************************************************/
 6 #include <iostream>
 7 #include <cstdio>
 8 #include <cstring>
 9 #include <algorithm>
10 using namespace std;
11 
12 #define lson rt << 1
13 #define rson rt << 1 | 1
14 const int MAXN = (200000 + 200);
15 template < class T > inline T getMax(const T &a, const T &b)
16 {
17     return a > b ? a : b;
18 }
19 
20 int sum[MAXN << 2];
21 int N, M;
22 
23 void PushUp(int rt)
24 {
25     sum[rt] = getMax(sum[lson], sum[rson]);
26 }
27 
28 void Build(int L, int R, int rt)
29 {
30     if (L == R) {
31         scanf("%d", &sum[rt]);
32         return;
33     }
34     int M = (L + R) >> 1;
35     Build(L, M, lson);
36     Build(M + 1, R, rson);
37     PushUp(rt);
38 }
39 
40 void Update(int L, int R, int rt, int p, int x)
41 {
42     if (L == R) {
43         sum[rt] = x;
44         return;
45     }
46     int M = (L + R) >> 1;
47     if (p <= M) {
48         Update(L, M, lson, p, x);
49     } else 
50         Update(M + 1, R, rson, p, x);
51     PushUp(rt);
52 }
53 
54 int Query(int L, int R, int rt, int l, int r)
55 {
56     if (l <= L && R <= r) {
57         return sum[rt];
58     }
59     int M = (L + R) >> 1;
60     int res = 0;
61     if (l <= M) res = getMax(res, Query(L, M, lson, l, r));
62     if (r > M) res = getMax(res, Query(M + 1, R, rson, l, r));
63     return res;
64 }
65 
66 int main()
67 {
68     while (cin >> N >> M) {
69         Build(1, N, 1);
70         while (M--) {
71             char str[11];
72             int x, y;
73             scanf("%s", str);
74             if (str[0] == 'U') {
75                 scanf("%d %d", &x, &y);
76                 Update(1, N, 1, x, y);
77             } else if (str[0] == 'Q') {
78                 scanf("%d %d", &x, &y);
79                 int ans =  Query(1, N, 1, x, y);
80                 printf("%d\n", ans);
81             }
82         }
83     }
84     return 0;
85 }
View Code

 http://acm.hdu.edu.cn/showproblem.php?pid=1394

可以先求开始序列的逆序数,一开始记录每个叶子节点的值为0,然后对于每个数,插入之后更新一下,对于当前的x[i],需要插叙[x[i], n - 1]之间的数已经出现了多少个。求出一开始的逆序数之后,就可以通过递推关系式以此找出后面的逆序数对。

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 #define lson rt << 1
 9 #define rson rt << 1 | 1
10 const int MAXN = (5000 + 50);
11 template < class T > inline T getMIN(const T &a, const T &b)
12 {
13     return a < b ? a : b;
14 }
15 int sum[MAXN << 2];
16 
17 void PushUp(int rt)
18 {
19     sum[rt] = sum[lson] + sum[rson];
20 }
21 
22 void Build(int L, int R, int rt)
23 {
24     sum[rt] = 0;
25     if (L == R) return;
26     int M = (L + R) >> 1;
27     Build(L, M, lson);
28     Build(M + 1, R, rson);
29 }
30 
31 void Update(int L, int R, int rt, int p)
32 {
33     if (L == R) {
34         sum[rt]++;
35         return;
36     }
37     int M = (L + R) >> 1;
38     if (p <= M) Update(L, M, lson, p);
39     else Update(M + 1, R, rson, p);
40     PushUp(rt);
41 }
42 
43 int Query(int L, int R, int rt, int l, int r)
44 {
45     if (l <= L && R <= r) {
46         return sum[rt];
47     }
48     int M = (L + R) >> 1;
49     int ret = 0;
50     if (l <= M) ret += Query(L, M, lson, l, r);
51     if (r > M) ret += Query(M + 1, R, rson, l, r);
52     return ret;
53 }
54 
55 int n, num[MAXN];
56 int main()
57 {
58     while (~scanf("%d", &n)) {
59         for (int i = 0; i < n; i++) {
60             scanf("%d", &num[i]);
61         }
62         Build(0, n - 1, 1);
63         int sum = 0;
64         for (int i = 0; i < n; i++) {
65             sum += Query(0, n - 1, 1, num[i], n - 1);
66             Update(0, n - 1, 1, num[i]);
67         }
68         int ans = sum;
69         for (int i = 0; i < n; i++) {
70             sum += (n - num[i] - 1) - num[i];
71             ans = getMIN(ans, sum);
72         }
73         printf("%d\n", ans);
74     }
75     return 0;
76 }
View Code

http://acm.hdu.edu.cn/showproblem.php?pid=2795

这题的本质是区间最大值,这是线段树的长处。

叶子节点x表示board的x行还能放的长度,于是对于区间[a, b]就是表示第a行到b行所能放的最大的长度,那么我们可以从根节点开始比较,如果当前长度小于跟节点的值,就往左子树走,否则就往右子树走,达到叶子节点的时候,len[rt] -= x表示在这一行放置了长度为x的广告,于是剩下的长度就要减少了,然后在update就可以了。

 1 #define _CRT_SECURE_NO_WARNINGS
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 #define lson rt << 1
 9 #define rson rt << 1 | 1
10 const int MAXN = (200000 + 20);
11 int h, w, n;
12 int len[MAXN << 2];
13 
14 template< class T > inline T getMIN(const T &a, const T &b)
15 {
16     return a < b ? a : b;
17 }
18 
19 template< class T > inline T getMAX(const T &a, const T &b)
20 {
21     return a > b ? a : b;
22 }
23 
24 void PushUp(int rt)
25 {
26     len[rt] = getMAX(len[lson], len[rson]);
27 }
28 
29 void Build(int L, int R, int rt)
30 {
31     len[rt] = w;
32     if (L == R) return;
33     int M = (L + R) >> 1;
34     Build(L, M, lson);
35     Build(M + 1, R, rson);
36 }
37 
38 int Query(int L, int R, int rt, int x)
39 {
40     if (L == R) {
41         len[rt] -= x;
42         return L;
43     }
44     int M = (L + R) >> 1;
45     int ret = (len[lson] >= x ? Query(L, M, lson, x) : Query(M + 1, R, rson, x));
46     PushUp(rt);
47     return ret;
48 }
49 
50 int main()
51 {
52     int x;
53     while (~scanf("%d %d %d", &h, &w, &n)) {
54         h = getMIN(h, n);
55         Build(1, h, 1);
56         for (int i = 1; i <= n; i++) {
57             scanf("%d", &x);
58             if (x > len[1]) {
59                 puts("-1");
60                 continue;
61             }
62             printf("%d\n", Query(1, h, 1, x));
63         }
64     }
65     return 0;
66 }
View Code

http://poj.org/problem?id=2828

采用倒序插入,pos的意义就是找到一个位置,它的前面刚好有pos个空位,用一个empty数组记录区间[l,r]之间有多少个空位,然后进来一个p,比较左右子树的空位数,如果坐标的空位数 >= p,那么说明p应该放在左子树,否则,p应该放右子树,并且p还要减去左子树的空位数,因为右子树的空位数也是从0开始的。

 1 #define  _CRT_SECURE_NO_WARNINGS
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <cstring>
 5 #include <algorithm>
 6 using namespace std;
 7 
 8 #define lson rt << 1
 9 #define rson rt << 1 | 1
10 const int MAXN = (200000 + 20);
11 int empty[MAXN << 2];
12 int n, index, pos[MAXN], id[MAXN], ans[MAXN];
13 
14 void Build(int L, int R, int rt)
15 {
16     empty[rt] = R - L + 1;
17     if (L == R) return;
18     int M = (L + R) >> 1;
19     Build(L, M, lson);
20     Build(M + 1, R, rson);
21 }
22 
23 void Update(int L, int R, int rt, int p)
24 {
25     empty[rt]--;
26     if (L == R) {
27         index = L;
28         return;
29     }
30     int M = (L + R) >> 1;
31     if (empty[lson] >= p) Update(L, M, lson, p);
32     else p -= empty[lson], Update(M + 1, R, rson, p);
33 }
34 
35 int main()
36 {
37     while (~scanf("%d", &n)) {
38         for (int i = 1; i <= n; i++) {
39             scanf("%d %d", &pos[i], &id[i]);
40         }
41         Build(1, n, 1);
42         for (int i = n; i >= 1; i--) {
43             Update(1, n, 1, pos[i] + 1);
44             ans[index] = id[i];
45         }
46         for (int i = 1; i <= n; i++) {
47             printf(i == n ? "%d\n" : "%d ", ans[i]);
48         }
49     }
50     return 0;
51 }
View Code

http://poj.org/problem?id=2481

对n头牛先按S从小到大排序,在按E从大到小排序,这样每次计算一个,我们可以找比当前的e大的出现的数目,然后更新即可,线段树的查找和更新的复杂度均为n * log(n).

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 #define lson rt << 1
 8 #define rson rt << 1 | 1
 9 const int MAXN = (100000 + 100);
10 template< typename T > inline T getMAX(const T &a, const T &b)
11 {
12     return a > b ? a : b;
13 }
14 
15 struct Node {
16     int s, e, id;
17 } node[MAXN];
18 
19 int cmp(const Node &p, const Node &q)
20 {
21     if (p.s != q.s) {
22         return p.s < q.s;
23     }
24     return p.e > q.e;
25 }
26 
27 int N;
28 int sum[MAXN << 2];
29 
30 void PushUp(int rt)
31 {
32     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
33 }
34 
35 void Build(int L, int R, int rt)
36 {
37     sum[rt] = 0;
38     if (L == R) return;
39     int M = (L + R) >> 1;
40     Build(L, M, lson);
41     Build(M + 1, R, rson);
42 }
43 
44 void Update(int L, int R, int rt, int p)
45 {
46     if (L == R) {
47         sum[rt]++;
48         return;
49     }
50     int M = (L + R) >> 1;
51     if (p <= M) Update(L, M, lson, p);
52     else Update(M + 1, R, rson, p);
53     PushUp(rt);
54 }
55 
56 int Query(int L, int R, int rt, int l, int r)
57 {
58     if (l <= L && R <= r) {
59         return sum[rt];
60     }
61     int M = (L + R) >> 1;
62     int ret = 0;
63     if (l <= M) ret += Query(L, M, lson, l, r);
64     if (r > M) ret += Query(M + 1, R, rson, l, r);
65     return ret;
66 }
67 
68 
69 int ans[MAXN];
70 int MAX;
71 int main()
72 {
73     while (~scanf("%d", &N) && N) {
74         MAX = 0;
75         for (int i = 0; i < N; i++) {
76             scanf("%d %d", &node[i].s, &node[i].e);
77             MAX = getMAX(MAX, node[i].e);
78             node[i].id = i;
79         }
80         sort(node, node + N, cmp);
81         Build(1, MAX, 1);
82         ans[node[0].id] = 0;
83         Update(1, MAX, 1, node[0].e);
84         for (int i = 1; i < N; i++) {
85             if (node[i].s == node[i - 1].s && node[i].e == node[i - 1].e) {
86                 ans[node[i].id] = ans[node[i - 1].id];
87             } else
88                 ans[node[i].id] = Query(1, MAX, 1, node[i].e, MAX);
89             Update(1, MAX, 1, node[i].e);
90         }
91         for (int i = 0; i < N; i++) {
92             if (i == N - 1) printf("%d\n", ans[i]);
93             else printf("%d ", ans[i]);
94         }
95     }
96     return 0;
97 }
View Code

http://poj.org/problem?id=2182

len数组代表当前节点的区间还有的空位置,那么我们可以从后往前依次放位置,这样就能确定最后的序列了!

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 #define lson rt << 1
 8 #define rson rt << 1 | 1
 9 const int MAXN = (8000 + 80);
10 int len[MAXN << 2];
11 int num[MAXN], ans[MAXN], pos, N;
12 
13 void Build(int L, int R, int rt)
14 {
15     len[rt] = R - L + 1;
16     if (L == R) return;
17     int M = (L + R) >> 1;
18     Build(L, M, lson);
19     Build(M + 1, R, rson);
20 }
21 
22 void Update(int L, int R, int rt, int p)
23 {
24     len[rt]--;
25     if (L == R) {
26         pos = L;
27         return;
28     }
29     int M = (L + R) >> 1;
30     if (p <= len[lson]) Update(L, M, lson, p);
31     else Update(M + 1, R, rson, p - len[lson]);
32 }
33 
34 int main()
35 {
36     while (~scanf("%d", &N)) {
37         num[1] = 0;
38         for (int i = 2; i <= N; i++) {
39             scanf("%d", &num[i]);
40         }
41         Build(1, N, 1);
42         for (int i = N; i >= 1; i--) {
43             Update(1, N, 1, num[i] + 1);
44             ans[i] = pos;
45         }
46         for (int i = 1; i <= N; i++) {
47             printf("%d\n", ans[i]);
48         }
49     }
50     return 0;
51 }
View Code

 

 模块二:线段树成段更新。

http://acm.hdu.edu.cn/showproblem.php?pid=1698

col数组要来标记当前区间的值,一开始所有的区间都为0,然后我们更新的时候,如果当前的区间的col不为0,则说明该区间是纯的,此时,我们应该把这个区间的col往左右子树传,同时计算sum的值,由于是纯的,因此当前节点的左子树和当前节点的右子树的sum可以直接求得,然后在把当前的col改为0,表示当前节点覆盖的区间不纯。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 #define lson rt << 1
 8 #define rson rt << 1 | 1
 9 const int MAXN = (100000 + 100);
10 int N, M;
11 int col[MAXN << 2], sum[MAXN << 2];
12 
13 void PushDown(int rt, int len)
14 {
15     if (col[rt]) {
16         col[lson] = col[rson] = col[rt];
17         sum[lson] = (len - (len >> 1)) * col[rt];
18         sum[rson] = (len >> 1) * col[rt];
19         col[rt] = 0; //不纯洁
20     }
21 }
22 
23 void PushUp(int rt)
24 {
25     sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
26 }
27 
28 
29 void Build(int L, int R, int rt)
30 {
31     col[rt] = 0;
32     sum[rt] = 1;
33     if (L == R) return;
34     int M = (L + R) >> 1;
35     Build(L, M, lson);
36     Build(M + 1, R, rson);
37     PushUp(rt);
38 }
39 
40 void Update(int L, int R, int rt, int l, int r, int color)
41 {
42     if (l <= L && R <= r) {
43         col[rt] = color;
44         sum[rt] = (R - L + 1) * color;
45         return;
46     }
47     PushDown(rt, R - L + 1);
48     int M = (L + R) >> 1;
49     if (l <= M) Update(L, M, lson, l, r, color);
50     if (r > M) Update(M + 1, R, rson, l, r, color);
51     PushUp(rt);
52 }
53 
54 int main()
55 {
56     int Cas, t = 1;
57     scanf("%d", &Cas);
58     while (Cas--) {
59         scanf("%d %d", &N, &M);
60         Build(1, N, 1);
61         for (int i = 0; i < M; i++) {
62             int a, b, c;
63             scanf("%d %d %d", &a, &b, &c);
64             Update(1, N, 1, a, b, c);
65         }
66         printf("Case %d: The total value of the hook is %d.\n", t++, sum[1]);
67     }
68     return 0;
69 }
View Code

http://poj.org/problem?id=3468

线段树成段更新,采用lazy思想,记录增量,更新的时候只更新到段,等到下次更新或者查询的时候,碰到已经被标记过的,往下顺延就行。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 #define lson rt << 1
 8 #define rson rt << 1 | 1
 9 typedef long long ll;
10 const int MAXN = (100000 +100);
11 int N, Q;
12 ll sum[MAXN << 2], add[MAXN << 2];
13 
14 void PushUp(int rt)
15 {
16     sum[rt] = sum[lson] + sum[rson];
17 }
18 
19 void PushDown(int rt, int len)
20 {
21     if (add[rt]) {
22         add[lson] += add[rt];
23         add[rson] += add[rt];
24         sum[lson] += (len - (len >> 1)) * add[rt];
25         sum[rson] += (len >> 1) * add[rt];
26         add[rt] = 0;
27     }
28 }
29 
30 void Build(int L, int R, int rt)
31 {
32     add[rt] = 0;
33     if (L == R) {
34         scanf("%lld", &sum[rt]);
35         return;
36     }
37     int M = (L + R) >> 1;
38     Build(L, M, lson);
39     Build(M + 1, R, rson);
40     PushUp(rt);
41 }
42 
43 void Update(int L, int R, int rt, int l, int r, int lnc)
44 {
45     if (l <= L && R <= r) {
46         add[rt] += lnc;
47         sum[rt] += (R - L + 1) * lnc;
48         return;
49     }
50     PushDown(rt, R - L + 1);
51     int M = (L + R) >> 1;
52     if (l <= M) Update(L, M, lson, l, r, lnc);
53     if (r > M) Update(M + 1, R, rson, l, r, lnc);
54     PushUp(rt);
55 }
56 
57 ll Query(int L, int R, int rt, int l, int r)
58 {
59     if (l <= L && R <= r) {
60         return sum[rt];
61     }
62     PushDown(rt, R - L + 1);
63     int M = (L + R) >> 1;
64     ll ret = 0;
65     if (l <= M) ret += Query(L, M, lson, l, r);
66     if (r > M) ret += Query(M + 1, R, rson, l, r);
67     return ret;
68 }
69 
70 int main()
71 {
72     scanf("%d %d", &N, &Q);
73     Build(1, N, 1);
74     while (Q--) {
75         char str[2];
76         int a, b, c;
77         scanf("%s", str);
78         if (str[0] == 'Q') {
79             scanf("%d %d", &a, &b);
80             printf("%lld\n", Query(1, N, 1, a, b));
81         } else if (str[0] == 'C') {
82             scanf("%d %d %d", &a, &b, &c);
83             Update(1, N, 1, a, b, c);
84         }
85     }
86     return 0;
87 }
View Code

http://acm.cug.edu.cn/JudgeOnline/problem.php?id=1435

线段树成段更新,区间最值。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 #define lson rt << 1
  8 #define rson rt << 1 | 1
  9 typedef long long ll;
 10 const int MAXN = (100000 + 100);
 11 template < typename T > inline T getMIN(const T &a, const T &b)
 12 {
 13     return a < b ? a : b;
 14 }
 15 
 16 int N, M;
 17 ll MIN[MAXN << 2], add[MAXN << 2];
 18 
 19 void PushDown(int rt)
 20 {
 21     if (add[rt]) {
 22         add[lson] += add[rt];
 23         add[rson] += add[rt];
 24         MIN[lson] += add[rt];
 25         MIN[rson] += add[rt];
 26         add[rt] = 0;
 27     }
 28 }
 29 
 30 void PushUp(int rt)
 31 {
 32     MIN[rt] = getMIN(MIN[lson], MIN[rson]);
 33 }
 34 
 35 void Build(int L, int R, int rt)
 36 {
 37     add[rt] = 0;
 38     if (L == R) {
 39         scanf("%lld", &MIN[rt]);
 40         return;
 41     }
 42     int M = (L + R) >> 1;
 43     Build(L, M, lson);
 44     Build(M + 1, R, rson);
 45     PushUp(rt);
 46 }
 47 
 48 void Update(int L, int R, int rt, int l, int r, int lnc)
 49 {
 50     if (l <= L && R <= r) {
 51         add[rt] += lnc;
 52         MIN[rt] += lnc;
 53         return;
 54     }
 55     PushDown(rt);
 56     int M = (L + R) >> 1;
 57     if (l <= M) Update(L, M, lson, l, r, lnc);
 58     if (r > M) Update(M + 1, R, rson, l, r, lnc);
 59     PushUp(rt);
 60 }
 61 
 62 ll Query(int L, int R, int rt, int l, int r)
 63 {
 64     if (l <= L && R <= r) {
 65         return MIN[rt];
 66     }
 67     PushDown(rt);
 68     int M = (L + R) >> 1;
 69     ll ans = 1LL << 60;
 70     if (l <= M) ans = getMIN(ans, Query(L, M, lson, l, r));
 71     if (r > M) ans = getMIN(ans, Query(M + 1, R, rson, l, r));
 72     return ans;
 73 }
 74 
 75 int Judge(char *str)
 76 {
 77     int len = strlen(str), cnt = 0;
 78     for (int i = 0; i < len; ) {
 79         if (str[i] == ' ') {
 80             cnt++;
 81             while (i < len && str[i] == ' ') i++;
 82         } else
 83             i++;
 84     }
 85     return cnt;
 86 }
 87 
 88 int main()
 89 {
 90     while (~scanf("%d %d", &N, &M)) {
 91         Build(0, N - 1, 1);
 92         getchar();
 93         while (M--) {
 94             char str[22];
 95             int a, b, c;
 96             gets(str);
 97             if (Judge(str) == 1) {
 98                 sscanf(str, "%d %d", &a, &b);
 99                 if (a <= b) {
100                     printf("%lld\n", Query(0, N - 1, 1, a, b));
101                 } else
102                     printf("%lld\n", getMIN(Query(0, N - 1, 1, a, N - 1), Query(0, N - 1, 1, 0, b)));
103             } else if (Judge(str) == 2) {
104                 sscanf(str, "%d %d %d", &a, &b, &c);
105                 if (a <= b) {
106                     Update(0, N - 1, 1, a, b, c);
107                 } else {
108                     Update(0, N - 1, 1, 0, b, c);
109                     Update(0, N - 1, 1, a, N - 1, c);
110                 }
111             }
112         }
113     }
114     return 0;
115 }
View Code

http://poj.org/problem?id=2528

线段树 + 离散化。

http://www.notonlysuccess.com/index.php/segment-tree-complete/大牛的博客讲得很清楚!

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 #define lson rt << 1
 8 #define rson rt << 1 | 1
 9 const int MAXN = (100000 + 100);
10 struct Node {
11     int l, r;
12 } node[MAXN];
13 
14 bool Hash[MAXN];
15 int X[MAXN << 2];
16 int col[MAXN << 4];
17 int cnt, n, m;
18 
19 void PushDown(int rt)
20 {
21     if (col[rt] != -1) {
22         col[lson] = col[rson] = col[rt];
23         col[rt] = -1;
24     }
25 }
26 
27 void Update(int L, int R, int rt, int l, int r, int color)
28 {
29     if (l <= L && R <= r) {
30         col[rt] = color;
31         return;
32     }
33     PushDown(rt);
34     int M = (L + R) >> 1;
35     if (l <= M) Update(L, M, lson, l, r, color);
36     if (r > M) Update(M + 1, R, rson, l, r, color);
37 }
38 
39 void Query(int L, int R, int rt)
40 {
41     if (col[rt] != -1) {
42         if (!Hash[col[rt]]) cnt++;
43         Hash[col[rt]] = true;
44         return;
45     }
46     if (L == R) return;
47     int M = (L + R) >> 1;
48     Query(L, M, lson);
49     Query(M + 1, R, rson);
50 }
51 
52 int Binary_Search(int low, int high, int number)
53 {
54     while (low <= high) {
55         int mid = (low + high) >> 1;
56         if (X[mid] == number) return mid;
57         else if (X[mid] < number) low = mid +1;
58         else high = mid - 1;
59     }
60     return low;
61 }
62 
63 int main()
64 {
65     int Cas;
66     scanf("%d", &Cas);
67     while (Cas--) {
68         scanf("%d", &m);
69         cnt = n = 0;
70         for (int i = 0; i < m; i++) {
71             scanf("%d %d", &node[i].l, &node[i].r);
72             X[n++] = node[i].l;
73             X[n++] = node[i].r;
74         }
75         sort(X, X + n);
76         n = unique(X, X + n) - X;
77         for (int i = n - 1; i > 0; i--) {
78             if (X[i] != X[i - 1] + 1) X[n++] = X[i - 1] + 1;
79         }
80         sort(X, X + n);
81         memset(col, -1, sizeof(col));
82         for (int i = 0; i < m; i++) {
83             int l = Binary_Search(0, n - 1, node[i].l);
84             int r = Binary_Search(0, n - 1, node[i].r);
85             Update(0, n - 1, 1, l, r, i);
86         }
87         memset(Hash, false, sizeof(Hash));
88         Query(0, n - 1, 1);
89         printf("%d\n", cnt);
90     }
91     return 0;
92 }
View Code

http://poj.org/problem?id=3225

线段树:区间异或,成段更新。

集合操作:

U: 把区间[l, r]覆盖成1

I: 把区间(-oo, l)和(r, +oo)覆盖成0

D:把区间(l, r) 覆盖成0

C: 把区间(-oo, l)和(r, +oo)覆盖成0,并且把[l, r]区间0、1互换

S: 把区间[l, r]0、1互换

0、1互换的过程实际上也就是异或的过程;

成段更新操作与之前的类似,不同的是异或的操作。

显然,当一个区间被覆盖后,不管之前有没有异或标记都没有意义了,因此应该把异或标记清0;

当一个节点得到异或标记的时候,应该先判断该节点的覆盖标记,如果该节点的覆盖标记为0/1(标记为-1,表示不是完全包含或者完全不包含),直接改变覆盖标记,否则改变异或标记。

至于如果来区别开闭区间,我们可以将区间扩大两倍,即:

左闭:x - > 2 * x 

左开: x - > 2 * x + 1

右闭:y - > 2 * y;

右开: y - > 2 * y - 1

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 using namespace std;
  6 
  7 #define lson rt << 1
  8 #define rson rt << 1 | 1
  9 const int MAXN  = (65537 << 1);
 10 bool mark[MAXN];
 11 int cover[MAXN << 2];
 12 int XOR[MAXN << 2];
 13 
 14 void FXOR(int rt)
 15 {
 16     if (cover[rt] != -1) {
 17         cover[rt] ^= 1;
 18     } else
 19         XOR[rt] ^= 1;
 20 }
 21 
 22 void PushDown(int rt)
 23 {
 24     if (cover[rt] != -1) {
 25         cover[lson] = cover[rson] = cover[rt];
 26         XOR[lson] = XOR[rson] = 0;
 27         cover[rt] = -1;
 28     }
 29     if (XOR[rt]) {
 30         FXOR(lson);
 31         FXOR(rson);
 32         XOR[rt] = 0;
 33     }
 34 }
 35 
 36 void Update(int L, int R, int rt, int l, int r, char ch)
 37 {
 38     if (l <= L && R <= r) {
 39         if (ch == 'U') {
 40             cover[rt] = 1;
 41             XOR[rt] = 0;
 42         } else if (ch == 'D') {
 43             cover[rt] = 0;
 44             XOR[rt] = 0;
 45         } else if (ch == 'C' || ch == 'S') {
 46             FXOR(rt);
 47         }
 48         return;
 49     }
 50     PushDown(rt);
 51     int M = (L + R) >> 1;
 52     if (l <= M) Update(L, M, lson, l, r, ch);
 53     else if (ch == 'I' || ch == 'C') {
 54         XOR[lson] = cover[lson] = 0;
 55     }
 56     if (r > M) Update(M + 1, R, rson, l, r, ch);
 57     else if (ch == 'I' || ch == 'C') {
 58         XOR[rson] = cover[rson] = 0;
 59     }
 60 }
 61 
 62 void Query(int L, int R, int rt)
 63 {
 64     if (cover[rt] != -1) {
 65         if (cover[rt] == 1) {
 66             for (int i = L; i <= R; i++) {
 67                 mark[i] = true;
 68             }
 69         }
 70         return;
 71     }
 72     PushDown(rt);
 73     int M = (L + R) >> 1;
 74     Query(L, M, lson);
 75     Query(M + 1, R, rson);
 76 }
 77 
 78 int main()
 79 {
 80     cover[1] = XOR[1] = 0;
 81     char ch, op1, op2;
 82     int a, b;
 83     memset(mark, false, sizeof(mark));
 84     while (~scanf("%c %c%d,%d%c\n", &ch, &op1, &a, &b, &op2)) {
 85         a <<= 1;
 86         b <<= 1;
 87         if (op1 == '(') {
 88             a++;
 89         }
 90         if (op2 == ')') {
 91             b--;
 92         }
 93         if (a > b) {
 94             if (ch == 'I' || ch == 'C') {
 95                 cover[1] = XOR[1] = 0;
 96             }
 97         } else
 98             Update(0, MAXN, 1, a, b, ch);
 99     }
100     Query(0, MAXN, 1);
101     bool flag = false;
102     int st = -1, ed;
103     for (int i = 0; i <= MAXN; i++) {
104         if (mark[i]) {
105             if (st == -1) st = i;
106             ed = i;
107         } else {
108             if (st != -1) {
109                 if (flag) printf(" ");
110                 flag = true;
111                 printf("%c%d,%d%c", st & 1 ? '(' : '[', st >> 1, (ed + 1) >> 1, ed & 1 ? ')' : ']');
112                 st = -1;
113             }
114         }
115     }
116     if (!flag) printf("empty set");
117     puts("");
118     return 0;
119 }
View Code

 

posted @ 2014-03-20 22:22  ihge2k  阅读(1522)  评论(0编辑  收藏  举报