线段树专题训练

模块一:

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

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

 

你可能感兴趣的:(线段树)