模块一:

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

​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) :  把父亲节点的信息更新到儿子节点。


线段树专题训练_#define线段树专题训练_i++_02


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]之间的数已经出现了多少个。求出一开始的逆序数之后,就可以通过递推关系式以此找出后面的逆序数对。


线段树专题训练_#define线段树专题训练_i++_02


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就可以了。


线段树专题训练_#define线段树专题训练_i++_02


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开始的。


线段树专题训练_#define线段树专题训练_i++_02


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).


线段树专题训练_#define线段树专题训练_i++_02


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


线段树专题训练_#define线段树专题训练_i++_02


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,表示当前节点覆盖的区间不纯。


线段树专题训练_#define线段树专题训练_i++_02


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思想,记录增量,更新的时候只更新到段,等到下次更新或者查询的时候,碰到已经被标记过的,往下顺延就行。


线段树专题训练_#define线段树专题训练_i++_02


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​

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


线段树专题训练_#define线段树专题训练_i++_02


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/​​大牛的博客讲得很清楚!


线段树专题训练_#define线段树专题训练_i++_02


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


线段树专题训练_#define线段树专题训练_i++_02


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