首先说下我写的线段树吧。

我是按照线段树【完全版】那个人的写法来写的,因为网上大多数题解都是按照他的写法来写。

确实比较飘逸,所以就借用了。

节点大小是maxn是4倍,准确来说是大于maxn的2^x次方的最小值的两倍。

lson 和 rson 用宏定义写了。因为是固定的量。

线段树不必保存自身的区间,因为一边传递过去的时候,在函数里就有区间表示,无谓开多些无用的变量。

pushUp函数,更新当前节点cur的值,其实就是,线段树一般都是处理完左右孩子,然后再递归更新父亲的嘛,这个pushUp函数就是用来更新父亲的。感觉不用这个函数更加清楚明了。

pushDown函数,在lazy--upDate的时候有用,作用是把延迟标记更新到左右节点。

多次使用sum不用清0,add要。build的时候就会初始化sum数据。但其他用法就可能要

  1. #define lson L, mid, cur << 1
  2. #define rson mid + 1, R, cur << 1 | 1
  3. void pushUp(int cur) {
  4. sum[cur] = sum[cur << ] + sum[cur << | ];
  5. }
  6. void pushDown(int cur, int total) {
  7. if (add[cur]) {
  8. add[cur << ] += add[cur]; //传递去左右孩子
  9. add[cur << | ] += add[cur]; // val >> 1 相当于 val / 2
  10. sum[cur << ] += add[cur] * (total - (total >> )); //左孩子有多少个节点
  11. sum[cur << | ] += add[cur] * (total >> ); //一共控制11个,则右孩子有5个
  12. add[cur] = ;
  13. }
  14. }
  15. void build(int L, int R, int cur) {
  16. if (L == R) {
  17. sum[cur] = a[L];
  18. return;
  19. }
  20. int mid = (L + R) >> ;
  21. build(lson);
  22. build(rson);
  23. pushUp(cur);
  24. }
  25. void upDate(int begin, int end, int val, int L, int R, int cur) {
  26. if (L >= begin && R <= end) {
  27. add[cur] += val;
  28. sum[cur] += val * (R - L + ); //这里加了一次,后面pushDown就只能用add[cur]的
  29. return;
  30. }
  31. pushDown(cur, R - L + ); //这个是必须的,因为下面的pushUp是直接等于的
  32. //所以要先把加的,传递去右孩子,然后父亲又调用pushUp,才能保证正确性。
  33. int mid = (L + R) >> ; //一直分解的是大区间,开始时是[1, n]这个区间。
  34. if (begin <= mid) upDate(begin, end, val, lson); //只要区间涉及,就必须更新
  35. if (end > mid) upDate(begin, end, val, rson);
  36. pushUp(cur);
  37. }
  38. int query(int begin, int end, int L, int R, int cur) {
  39. if (L >= begin && R <= end) {
  40. return sum[cur];
  41. }
  42. pushDown(cur, R - L + );
  43. int ans = , mid = (L + R) >> ;
  44. if (begin <= mid) ans += query(begin, end, lson); //只要区间涉及,就必须查询
  45. if (end > mid) ans += query(begin, end, rson);
  46. return ans;
  47. }

成段更新模板

关于成段更新时的upDate函数,中途的pushDown是不能省的,可以看看第三题然后结合我给的数据(数据是poj的大牛发出来的,不是我想的。)关键就在于pushUp函数是直接等于的,你不pushDown,然后pushUp,就会把以前的增加值给抹杀了

HDU 1166    敌兵布阵

单点更新,区间求和

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

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15. #include <queue>
  16. #include <string>
  17. #define lson L, mid, cur << 1
  18. #define rson mid + 1, R, cur << 1 | 1
  19. const int maxn = + ;
  20. int sum[maxn << ];
  21. int a[maxn];
  22. void pushUp(int cur) { //更新当前这个节点的信息
  23. sum[cur] = sum[cur << ] + sum[cur << | ];
  24. }
  25. void build(int L, int R, int cur) {
  26. if (L == R) {
  27. sum[cur] = a[L];
  28. return;
  29. }
  30. int mid = (L + R) >> ;
  31. build(lson);
  32. build(rson);
  33. pushUp(cur);
  34. }
  35. void upDate(int pos, int val, int L, int R, int cur) {
  36. if (L == pos && R == pos) {
  37. sum[cur] += val;
  38. return;
  39. }
  40. int mid = (L + R) >> ;
  41. if (pos <= mid) upDate(pos, val, lson);
  42. else upDate(pos, val, rson);
  43. pushUp(cur);
  44. }
  45. int query(int begin, int end, int L, int R, int cur) { //[L, R]大区间, [begin, end]查询区间
  46. if (L >= begin && R <= end) { //这个大区间是待查区间的子集
  47. return sum[cur];
  48. }
  49. int mid = (L + R) >> ;
  50. int ans = ;
  51. if (begin <= mid) ans += query(begin, end, lson);
  52. if (end > mid) ans += query(begin, end, rson);
  53. return ans;
  54. }
  55. int f;
  56. void work() {
  57. printf("Case %d:\n", ++f);
  58. int n;
  59. scanf("%d", &n);
  60. for (int i = ; i <= n; ++i) {
  61. scanf("%d", &a[i]);
  62. }
  63. build(, n, );
  64. char cmd[];
  65. while (scanf("%s", cmd) != EOF && cmd[] != 'E') {
  66. int a, b;
  67. scanf("%d%d", &a, &b);
  68. if (cmd[] == 'Q') {
  69. printf("%d\n", query(a, b, , n, ));
  70. } else if (cmd[] == 'A') {
  71. upDate(a, b, , n, );
  72. } else {
  73. upDate(a, -b, , n, );
  74. }
  75. }
  76. return;
  77. }
  78.  
  79. int main() {
  80. #ifdef local
  81. freopen("data.txt","r",stdin);
  82. #endif
  83. int t;
  84. scanf("%d", &t);
  85. while (t--) {
  86. work();
  87. }
  88. return ;
  89. }

HDU 1754  I Hate It

单点更新,区间最值

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

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15. #include <queue>
  16. #include <string>
  17. #define lson L, mid, cur << 1
  18. #define rson mid + 1, R, cur << 1 | 1
  19. const int maxn = + ;
  20. int mx[maxn << ];
  21. int a[maxn];
  22. void pushUp(int cur) {
  23. mx[cur] = max(mx[cur << ], mx[cur << | ]);
  24. }
  25. void build(int L, int R, int cur) {
  26. if (L == R) {
  27. mx[cur] = a[L]; //就是自己
  28. return;
  29. }
  30. int mid = (L + R) >> ;
  31. build(lson);
  32. build(rson);
  33. pushUp(cur);
  34. }
  35. void upDate(int pos, int val, int L, int R, int cur) {
  36. if (L == pos && R == pos) { //精确到这一个点
  37. mx[cur] = val;
  38. return;
  39. }
  40. int mid = (L + R) >> ;
  41. if (pos <= mid) upDate(pos, val, lson);
  42. else upDate(pos, val, rson);
  43. pushUp(cur);
  44. }
  45. int query(int begin, int end, int L, int R, int cur) {
  46. if (L >= begin && R <= end) {
  47. return mx[cur];
  48. }
  49. int mid = (L + R) >> ;
  50. int ans = ;
  51. if (begin <= mid) ans = query(begin, end, lson); //区间有涉及,级要查询
  52. if (end > mid) ans = max(ans, query(begin, end, rson));
  53. return ans;
  54. }
  55. int n, m;
  56. void work() {
  57. for (int i = ; i <= n; ++i) {
  58. scanf("%d", &a[i]);
  59. }
  60. build(, n, );
  61. for (int i = ; i <= m; ++i) {
  62. char str[];
  63. int b, c;
  64. scanf("%s%d%d", str, &b, &c);
  65. if (str[] == 'Q') {
  66. printf("%d\n", query(b, c, , n, ));
  67. } else upDate(b, c, , n, );
  68. }
  69. }
  70.  
  71. int main() {
  72. #ifdef local
  73. freopen("data.txt","r",stdin);
  74. #endif
  75. while (scanf("%d%d", &n, &m) != EOF) {
  76. work();
  77. }
  78. return ;
  79. }

POJ 3468 A Simple Problem with Integers

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

成段更新,区间查询总和,这题记得用LL,

给个数据

  1. 10 22
  2. 1 2 3 4 5 6 7 8 9 10
  3. Q 4 4
  4. C 1 10 3
  5. C 6 10 3
  6. C 6 9 3
  7. C 8 9 -100
  8. C 7 9 3
  9. C 7 10 3
  10. C 1 10 3
  11. Q 6 10
  12. Q 6 9
  13. Q 8 9
  14. Q 7 9
  15. Q 7 10
  16. Q 1 10
  17. Q 2 4
  18. C 3 6 3
  19. Q 9 9
  20. Q 1 1
  21. Q 5 5
  22. Q 6 6
  23. Q 7 7
  24. Q 6 8
  25.  
  26. ans
  27.  
  28. 4
  29. -82
  30. -104
  31. -147
  32. -122
  33. -100
  34. -37
  35. 27
  36. -73
  37. 7
  38. 14
  39. 21
  40. 25
  41. -28
  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15.  
  16. #define lson L, mid, cur << 1
  17. #define rson mid + 1, R, cur << 1 | 1
  18. const int maxn = + ;
  19. LL sum[maxn << ];
  20. LL add[maxn << ];
  21. int a[maxn];
  22. void pushUp(int cur) {
  23. sum[cur] = sum[cur << ] + sum[cur << | ];
  24. }
  25. void pushDown(int cur, int total) {
  26. if (add[cur]) {
  27. add[cur << ] += add[cur];
  28. add[cur << | ] += add[cur]; // val >> 1 相当于 val / 2
  29. sum[cur << ] += add[cur] * (total - (total >> )); //左孩子有多少个节点
  30. sum[cur << | ] += add[cur] * (total >> ); //一共控制11个,则右孩子有5个
  31. add[cur] = ;
  32. }
  33. }
  34. void build(int L, int R, int cur) {
  35. if (L == R) {
  36. sum[cur] = a[L];
  37. return;
  38. }
  39. int mid = (L + R) >> ;
  40. build(lson);
  41. build(rson);
  42. pushUp(cur);
  43. }
  44. void upDate(int begin, int end, LL val, int L, int R, int cur) {
  45. if (L >= begin && R <= end) {
  46. add[cur] += val;//这里加了一次,后面pushDown就只能用add[cur]的
  47. sum[cur] += val * (R - L + ); //控制的节点数目
  48. return;
  49. }
  50. pushDown(cur, R - L + );
  51. int mid = (L + R) >> ;
  52. if (begin <= mid) upDate(begin, end, val, lson);
  53. if (end > mid) upDate(begin, end, val, rson);
  54. pushUp(cur);
  55. }
  56. LL query(int begin, int end, int L, int R, int cur) {
  57. if (L >= begin && R <= end) {
  58. return sum[cur];
  59. }
  60. pushDown(cur, R - L + );
  61. LL ans = , mid = (L + R) >> ;
  62. if (begin <= mid) ans += query(begin, end, lson);
  63. if (end > mid) ans += query(begin, end, rson);
  64. return ans;
  65. }
  66. void work() {
  67. int n, q;
  68. scanf("%d%d", &n, &q);
  69. for (int i = ; i <= n; ++i) {
  70. scanf("%d", &a[i]);
  71. }
  72. build(, n, );
  73. char str[];
  74. for (int i = ; i <= q; ++i) {
  75. scanf("%s", str);
  76. int L, R, val;
  77. if (str[] == 'Q') {
  78. scanf("%d%d", &L, &R);
  79. printf("%I64d\n", query(L, R, , n, ));
  80. } else {
  81. scanf("%d%d%d", &L, &R, &val);
  82. upDate(L, R, val, , n, );
  83. }
  84. }
  85. return;
  86. }
  87. int main() {
  88. #ifdef local
  89. freopen("data.txt","r",stdin);
  90. #endif
  91. work();
  92. return ;
  93. }

HDU 1698 Just a Hook

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

线段树成段覆盖成一个值,然后求总和。

思路是:用线段树覆盖整一段的值,然后每次更新,也是延迟标记加速。不同的是:每次更新的时候,线段树节点覆盖的总和不是加上去而是直接等于,因为后面一段都变成了这个数字嘛。。前面的值就相当于没用了。。所以sum[1]就是答案

然后记得memset add

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15. #include <queue>
  16. #include <string>
  17. #define lson L, mid, cur << 1
  18. #define rson mid + 1, R, cur << 1 | 1
  19. const int maxn = + ;
  20. int add[maxn << ];
  21. int sum[maxn << ];
  22. void pushDown(int cur, int total) {
  23. if (add[cur]) {
  24. add[cur << ] = add[cur];
  25. add[cur << | ] = add[cur];
  26. sum[cur << ] = add[cur] * (total - (total >> ));
  27. sum[cur << | ] = add[cur] * (total >> );
  28. add[cur] = ;
  29. }
  30. }
  31. void pushUp(int cur) {
  32. sum[cur] = sum[cur << ] + sum[cur << | ];
  33. }
  34. void upDate(int begin, int end, int val, int L, int R, int cur) {
  35. if (L >= begin && R <= end) {
  36. add[cur] = val;
  37. sum[cur] = val * (R - L + );
  38. return;
  39. }
  40. pushDown(cur, R - L + );
  41. int mid = (L + R) >> ;
  42. if (begin <= mid) upDate(begin, end, val, lson);
  43. if (end > mid) upDate(begin, end, val, rson);
  44. pushUp(cur);
  45. }
  46. //int query(int begin, int end, int L, int R, int cur) {
  47. // if (L >= begin && R <= end) {
  48. // return sum[cur];
  49. // }
  50. // pushDown(cur, R - L + 1);
  51. // int mid = (L + R) >> 1;
  52. // int ans = 0;
  53. //
  54. //}
  55. void build(int L, int R, int cur) {
  56. if (L == R) {
  57. sum[cur] = ;
  58. return;
  59. }
  60. int mid = (L + R) >> ;
  61. build(lson);
  62. build(rson);
  63. pushUp(cur);
  64. }
  65. int f;
  66. void work() {
  67. int n;
  68. scanf("%d", &n);
  69. build(, n, );
  70. // cout << sum[2] << endl;
  71. int m;
  72. scanf("%d", &m);
  73. for (int i = ; i <= m; ++i) {
  74. int L, R, val;
  75. scanf("%d%d%d", &L, &R, &val);
  76. upDate(L, R, val, , n, );
  77. // cout << L << " " << R << " " << val << endl;
  78.  
  79. // cout << sum[3] << endl;
  80. }
  81. printf("Case %d: The total value of the hook is %d.\n", ++f, sum[]);
  82. }
  83.  
  84. int main() {
  85. #ifdef local
  86. freopen("data.txt","r",stdin);
  87. #endif
  88. int t;
  89. cin >> t;
  90. while (t--) {
  91. work();
  92. memset(add, , sizeof add);
  93. }
  94. return ;
  95. }

可以用a[cur]表示这个 节点所保存的相同值的总和。就是a[cur]保存的是它所维护的区间,数字都是val这一个的总和。

然后query一下即可。

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15. #include <queue>
  16. #include <string>
  17. #define lson L, mid, cur << 1
  18. #define rson mid + 1, R, cur << 1 | 1
  19. const int maxn = + ;
  20. int a[maxn << ];
  21. void pushDown(int cur, int total) {
  22. if (a[cur]) {
  23. a[cur << ] = (total - (total >> )) * (a[cur] / total);
  24. a[cur << | ] = (total >> ) * (a[cur] / total);
  25. a[cur] = ;
  26. }
  27. }
  28. void upDate(int begin, int end, int val, int L, int R, int cur) {
  29. if (L >= begin && R <= end) {
  30. a[cur] = (R - L + ) * val;
  31. return;
  32. }
  33. pushDown(cur, R - L + );
  34. int mid = (L + R) >> ;
  35. if (begin <= mid) upDate(begin, end, val, lson);
  36. if (end > mid) upDate(begin, end, val, rson);
  37. }
  38. int query(int L, int R, int cur) {
  39. if (a[cur]) {
  40. return a[cur];
  41. }
  42. if (L == R) {
  43. while ();
  44. return ;
  45. }
  46. int mid = (L + R) >> ;
  47. int ans = query(lson) + query(rson);
  48. return ans;
  49. }
  50. int f;
  51. void work() {
  52. int n, q;
  53. cin >> n >> q;
  54. a[] = n;
  55. for (int i = ; i <= q; ++i) {
  56. int L, R, val;
  57. scanf("%d%d%d", &L, &R, &val);
  58. upDate(L, R, val, , n, );
  59. }
  60. printf("Case %d: The total value of the hook is %d.\n", ++f, query(, n, ));
  61. }
  62.  
  63. int main() {
  64. #ifdef local
  65. freopen("data.txt","r",stdin);
  66. #endif
  67. int t;
  68. scanf("%d", &t);
  69. while (t--) {
  70. work();
  71. }
  72. return ;
  73. }

POJ 2528 Mayor's posters

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

离散化。

一开始就知道要离散化的了,但觉得离散化后保证不了答案的正确性呀?(其实是还没懂的什么叫离散化)

可以这样去想。如果[L1, R1]和[L2, R2]已知,那么,同时放大或者缩小若干倍,是不影响其相交性的。

比如[1, 6]和[3, 7]离散后[1, 3]和[2, 4],一样是这样的相交。只不过露出来的部分确实少了点,但是不影响我们的答案。

所以可以离散化后线段树搞一搞。也是区间成段替换的题目。

离散的时候 有bug

[1, 10]

[1, 4]

[6,  10] 的话。直接离散是错误的。这个ans应该是3.

但是直接离散后,[1, 4] [1, 2] [3,4]使得ans = 2;

是因为忽略了5这样的错误。解决方法就是如果数字隔开了,补上一个数字,这样离散后就不会挨着了。

线段树思路:用seg[cur]表示cur这个节点控制的区间的值。就是seg[1] = val表示[1, n]这段区间的值都是val

然后直接pushDown即可,pushUp就不用了。(传递下去后可以把当前的清空了)

每次询问,hash一下这个值有没出现过就行。每次判断玩后,直接return了,不要找它儿子了。因为可能后来延迟标记的没延迟标记下去。不然就pushdown一下

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15. #include <queue>
  16. #include <string>
  17. #define lson L, mid, cur << 1
  18. #define rson mid + 1, R, cur << 1 | 1
  19. const int maxn = * + ;
  20. int all[maxn];
  21. int L[maxn];
  22. int R[maxn];
  23. set<int>number;
  24. int seg[maxn << ];
  25. void pushDown(int cur) {
  26. if (seg[cur]) {
  27. seg[cur << ] = seg[cur << | ] = seg[cur];
  28. seg[cur] = ;
  29. }
  30. }
  31. void upDate(int begin, int end, int val, int L, int R, int cur) {
  32. if (L >= begin && R <= end) {
  33. seg[cur] = val;
  34. return;
  35. }
  36. pushDown(cur);
  37. int mid = (L + R) >> ;
  38. if (begin <= mid) upDate(begin, end, val, lson);
  39. if (end > mid) upDate(begin, end, val, rson);
  40. }
  41. bool hash[maxn];
  42. int ans;
  43. void query(int L, int R, int cur) {
  44. if (seg[cur]) {
  45. if (!hash[seg[cur]]) {
  46. hash[seg[cur]] = ;
  47. ans++;
  48. }
  49. // return;
  50. }
  51. pushDown(cur); //不return就pushDown
  52. if (L == R) return;
  53. int mid = (L + R) >> ;
  54. query(lson);
  55. query(rson);
  56. }
  57. void work() {
  58. int n;
  59. scanf("%d", &n);
  60. number.clear();
  61. memset(seg, , sizeof seg);
  62. for (int i = ; i <= n; ++i) {
  63. scanf("%d%d", &L[i], &R[i]);
  64. number.insert(L[i]);
  65. number.insert(R[i]);
  66. }
  67. int lenall = ;
  68. for (set<int> :: iterator it = number.begin(); it != number.end(); ++it) {
  69. all[++lenall] = *it; //去重
  70. }
  71. int t = lenall;
  72. for (int i = ; i <= t; ++i) {
  73. if (all[i] != all[i - ] + ) {
  74. all[++lenall] = all[i - ] + ;
  75. }
  76. }
  77. sort(all + , all + + lenall);
  78. for (int i = ; i <= n; ++i) {
  79. int begin = lower_bound(all + , all + + lenall, L[i]) - all;
  80. int end = lower_bound(all + , all + + lenall, R[i]) - all;
  81. upDate(begin, end, i, , lenall, );
  82. }
  83. ans = ;
  84. memset(hash, , sizeof hash);
  85. query(, lenall, );
  86. cout << ans << endl;
  87. }
  88. int main() {
  89. #ifdef local
  90. freopen("data.txt","r",stdin);
  91. #endif
  92. int t;
  93. scanf("%d", &t);
  94. while (t--) work();
  95. return ;
  96. }

HDU 4027

Can you answer these queries?

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

有一个很明显的道理就是如果那个开放数是1了,其实就没必要开放了。

同样是用sum[cur]表示这个节点控制的总和。然后用个book[cur]表示这个节点控制的区间的值是否全部是1.

由于开放不超7次就会变成1了。所以可以暴力单点更新。然后把book[cur]传递上去就行。

book[cur]为1(不用更新了)的前提是左右儿子都不用更新。还有叶子节点是不会pushUp的(return了),以前理解错误。

注意一个坑爹点,就是L可能大于R

sum不用清0,因为每次都重新输入值了,而且不用考虑叶子节点后面的节点,用不上的。

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15. #include <queue>
  16. #include <string>
  17. #define lson L, mid, cur << 1
  18. #define rson mid + 1, R, cur << 1 | 1
  19. const int maxn = + ;
  20. LL sum[maxn << ];
  21. bool book[maxn << ];//查看是否还有更新的必要
  22. int n;
  23. void pushUp(int cur) {
  24. sum[cur] = sum[cur << ] + sum[cur << | ];
  25. book[cur] = book[cur << ] && book[cur << | ]; //左右孩子都不用更新了,就不更新了
  26. }
  27. void build(int L, int R, int cur) {
  28. if (L == R) {
  29. scanf("%I64d", &sum[cur]);
  30. return;
  31. }
  32. int mid = (L + R) >> ;
  33. build(lson);
  34. build(rson);
  35. pushUp(cur);
  36. }
  37. void upDate(int begin, int end, int L, int R, int cur) {
  38. if (L == R) { //暴力单点更新
  39. sum[cur] = (LL)sqrt(sum[cur] * 1.0);
  40. if (sum[cur] == ) { //已经等于1就不用更新了
  41. book[cur] = ;
  42. }
  43. return;
  44. }
  45. int mid = (L + R) >> ;
  46. if (begin <= mid && !book[cur << ]) upDate(begin, end, lson);
  47. if (end > mid && !book[cur << | ]) upDate(begin, end, rson);
  48. pushUp(cur);
  49. }
  50. LL query(int begin, int end, int L, int R, int cur) {
  51. if (L >= begin && R <= end) {
  52. return sum[cur];
  53. }
  54. int mid = (L + R) >> ;
  55. LL ans = ;
  56. if (begin <= mid) ans += query(begin, end, lson);
  57. if (end > mid) ans += query(begin, end, rson);
  58. return ans;
  59. }
  60. int f;
  61. void work() {
  62. printf("Case #%d:\n", ++f);
  63. build(, n, );
  64. int m;
  65. scanf("%d", &m);
  66. for (int i = ; i <= m; ++i) {
  67. int flag, L, R;
  68. scanf("%d%d%d", &flag, &L, &R);
  69. if (L > R) swap(L, R); //注意这个特别坑
  70. if (flag == ) {
  71. upDate(L, R, , n, );
  72. } else {
  73. printf("%I64d\n", query(L, R, , n, ));
  74. }
  75. }
  76. }
  77. int main() {
  78. #ifdef local
  79. freopen("data.txt","r",stdin);
  80. #endif
  81. while (scanf("%d", &n) != EOF) {
  82. work();
  83. memset(book, , sizeof book);
  84. printf("\n");
  85. }
  86. return ;
  87. }

线段树的区间合并

HDU 1540 Tunnel Warfare

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

点单更新,区间查询

对于一个数组[1, n]有三种操作,

1、可以删除一个元素,这样连续区间就会减小。

2、恢复上一次删除的那个元素。

3、给定一个位置pos,求出其最大的连续区间。

思路:查询的时候,就是这个点pos的左边连续最大 + 右边连续最大。(有一点分治的思想)

然后用2颗线段树维护。分别是LtoRsum[cur]表示,对于第cur个节点,其左端点,向右能延伸的最长距离。

就是假如这个节点维护的是区间[L, R],那么LtoRsum[cur]就表示从L开始,向右边最多能延伸的区间。

同理,RtoLsum[cur]就是这个区间的右端点,向左延伸的区间。

那么ans = [1, pos]中向左延伸的区间 + [pos, n]中向右延续的区间。

对于每次的pushUp。其思路就是,假如是LtoRsum[cur],先要满足其左孩子的值,如果左孩子丰满,才能加上右孩子的值。因为这样这个区间才是连续的。

具体看看代码模拟一下吧~~

恢复  and 删除那个。可以用0表示删除了,1表示没删除。单点更新即可、

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15. #include <queue>
  16. #include <string>
  17. #define root 1, n, 1
  18. #define lson L, mid, cur << 1
  19. #define rson mid + 1, R, cur << 1 | 1
  20. const int maxn = + ;
  21. int LtoRsum[maxn << ];
  22. int RtoLsum[maxn << ];
  23. bool book[maxn];
  24. void build(int L, int R, int cur) {
  25. LtoRsum[cur] = RtoLsum[cur] = R - L + ;
  26. if (L == R) return;
  27. int mid = (L + R) >> ;
  28. build(lson);
  29. build(rson);
  30. }
  31. void pushUp(int cur, int total) {
  32. LtoRsum[cur] = LtoRsum[cur << ];
  33. RtoLsum[cur] = RtoLsum[cur << | ];
  34. if (LtoRsum[cur] == (total - (total >> ))) { //如果左孩子都丰满了,就可以接着合并右孩子的值
  35. LtoRsum[cur] += LtoRsum[cur << | ];
  36. }
  37. if (RtoLsum[cur] == (total >> )) {
  38. RtoLsum[cur] += RtoLsum[cur << ];
  39. }
  40. }
  41. void upDate(int pos, int val, int L, int R, int cur) { //单点更新
  42. if (L == R) {
  43. LtoRsum[cur] = RtoLsum[cur] = val;
  44. return;
  45. }
  46. int mid = (L + R) >> ;
  47. if (pos <= mid) upDate(pos, val, lson);
  48. else upDate(pos, val, rson);
  49. pushUp(cur, R - L + );
  50. }
  51. int queryLtoRsum(int begin, int end, int L, int R, int cur) {
  52. if (L >= begin && R <= end) return LtoRsum[cur];
  53. int mid = (L + R) >> , lans = -inf, rans = -inf;
  54. if (begin <= mid) lans = queryLtoRsum(begin, end, lson);
  55. if (end > mid) rans = queryLtoRsum(begin, end, rson);
  56.  
  57. if (end <= mid) return lans; //只有左孩子
  58. if (begin > mid) return rans;
  59. if (lans == mid - begin + ) return lans + rans;
  60. //就是[begin, end]这个区间,的左孩子能够去到中间和右孩子汇合。
  61. return lans;
  62. }
  63. int queryRtoLsum(int begin, int end, int L, int R, int cur) {
  64. if (L >= begin && R <= end) return RtoLsum[cur];
  65. int mid = (L + R) >> , lans = -inf, rans = -inf;
  66. if (begin <= mid) lans = queryRtoLsum(begin, end, lson);
  67. if (end > mid) rans = queryRtoLsum(begin, end, rson);
  68.  
  69. if (begin > mid) return rans;
  70. if (end <= mid) return lans; //只有左孩子
  71. if (rans == end - mid) return rans + lans; //本来右孩子就少了一个
  72. return rans;
  73. }
  74. int n, m;
  75. int stack[maxn];
  76. int top;
  77. void work() {
  78. top = ;
  79. build(root);
  80. // cout << RtoLsum[14] << endl;
  81. // int a = 4;
  82. // int ans = queryLtoRsum(a, n, 1, n, 1) + queryRtoLsum(1, a, 1, n, 1);
  83. // printf("%d***\n", queryLtoRsum(a, n, 1, n, 1) );
  84. // printf("%d***\n", queryRtoLsum(1, a, 1, n, 1) );
  85. for (int i = ; i <= m; ++i) {
  86. char str[];
  87. int a;
  88. scanf("%s", str);
  89. if (str[] == 'D') {
  90. scanf("%d", &a);
  91. stack[++top] = a;
  92. upDate(a, , root);
  93. } else if (str[] == 'R') {
  94. upDate(stack[top], , root);
  95. --top;
  96. } else {
  97. scanf("%d", &a);
  98. int ans = queryLtoRsum(a, n, root) + queryRtoLsum(, a, root);
  99. printf("%d\n", ans == ? : ans - );
  100. }
  101. }
  102. }
  103.  
  104. int main() {
  105. #ifdef local
  106. freopen("data.txt","r",stdin);
  107. #endif
  108. while (scanf("%d%d", &n, &m) != EOF) work();
  109. return ;
  110. }

上一题的升级版  POJ 3667  Hotel

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

有两种操作,

1、查找第一个具有连续val个空位的点,就是找出第一个[L, L + val - 1]是空位的。然后占据,不存在输出0

2、占据[L, R]这段位置。

思路:对于2这样的操作,可以用lazy-update来做,和以前的区间覆盖一段数值是一样的。

关键是如何找出第一个位置,具有连续val个空位的。

用以前的那种暴力查找每个位置的值,显然就超时了。

考虑用一个sum[cur]表示这个节点所维护的区间的“最长连续空位置数目”

那么先判断总区间是否 > val,没有则直接是0了。

那么

1、如果左孩子有 > val个数目,则优先去找左孩子

2、如果是中间有 > val个数目,就是两个区间合并起来,连续数目 > val的,那么起点可以找出来了,就是mid - RtoLsum[cur << 1] + 1

3、去找右孩子

左孩子右端点向左,连续的最大数目。可以画图理解。

那么现在关键是怎么解出这个sum[cur]了,来源是三部分,第一是max(sum[cur << 1], sum[cur << 1 | 1])这个好理解,就是左右孩子能维护多少,就能更新到父亲那里去。然后关键就是有一部分是中间区间合并的,这段和就是RtoLsum[cur << 1] + LtoRsum[cur << 1 | 1],左孩子的右端点向左连续的个数 + 右孩子左端点向右连续的个数。这里不需要减去1,因为他们各自维护的区间是独立的,不会相交,不存在有一个数字相加了2次的情况。

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15. #include <queue>
  16. #include <string>
  17. #define root 1, n, 1
  18. #define lson L, mid, cur << 1
  19. #define rson mid + 1, R, cur << 1 | 1
  20. const int maxn = + ;
  21. int n, m;
  22. int LtoRsum[maxn << ];
  23. int RtoLsum[maxn << ];
  24. int add[maxn << ];
  25. int sum[maxn << ];
  26. void build(int L, int R, int cur) {
  27. sum[cur] = LtoRsum[cur] = RtoLsum[cur] = R - L + ;
  28. if (L == R) return;
  29. int mid = (L + R) >> ;
  30. build(lson);
  31. build(rson);
  32. }
  33. void pushDown(int cur, int total) {
  34. if (add[cur] != -) {
  35. add[cur << ] = add[cur << | ] = add[cur];
  36. if (add[cur]) {
  37. sum[cur << ] = LtoRsum[cur << ] = RtoLsum[cur << ] = (total - (total >> ));
  38. sum[cur << | ] = LtoRsum[cur << | ] = RtoLsum[cur << | ] = (total >> );
  39. } else {
  40. sum[cur << ] = LtoRsum[cur << ] = LtoRsum[cur << | ] = ;
  41. sum[cur << | ] = RtoLsum[cur << ] = RtoLsum[cur << | ] = ;
  42. }
  43. add[cur] = -;
  44. }
  45. }
  46. void pushUp(int cur, int total) {
  47. LtoRsum[cur] = LtoRsum[cur << ];
  48. RtoLsum[cur] = RtoLsum[cur << | ];
  49. if (LtoRsum[cur] == (total - (total >> ))) LtoRsum[cur] += LtoRsum[cur << | ];
  50. if (RtoLsum[cur] == (total >> )) RtoLsum[cur] += RtoLsum[cur << ];
  51. sum[cur] = max(max(sum[cur << ], sum[cur << | ]), LtoRsum[cur << | ] + RtoLsum[cur << ]);//区间相互独立,没交集,不用减去1
  52. }
  53. void upDate(int begin, int end, int val, int L, int R, int cur) {
  54. if (L >= begin && R <= end) {
  55. if (val) {
  56. sum[cur] = LtoRsum[cur] = RtoLsum[cur] = R - L + ;
  57. } else sum[cur] = LtoRsum[cur] = RtoLsum[cur] = ;
  58. add[cur] = val;
  59. return;
  60. }
  61. int mid = (L + R) >> ;
  62. pushDown(cur, R - L + );
  63. if (begin <= mid) upDate(begin, end, val, lson);
  64. if (end > mid) upDate(begin, end, val, rson);
  65. pushUp(cur, R - L + );
  66. }
  67. //int queryLtoRsum(int begin, int end, int L, int R, int cur) {
  68. // if (L >= begin && R <= end) return LtoRsum[cur];
  69. // pushDown(cur, R - L + 1);
  70. // int mid = (R + L) >> 1, lans = -inf, rans = -inf;
  71. // if (begin <= mid) lans = queryLtoRsum(begin, end, lson);
  72. // if (end > mid) rans = queryLtoRsum(begin, end, rson);
  73. //
  74. // if (end <= mid) return lans;
  75. // if (begin > mid) return rans;
  76. // if (lans == mid - begin + 1) return lans + rans;
  77. // return lans;
  78. //// printf("fff\n");
  79. //// while (1);
  80. //}
  81. //int queryRtoLsum(int begin, int end, int L, int R, int cur) {
  82. // if (L >= begin && R <= end) return RtoLsum[cur];
  83. // pushDown(cur, R - L + 1);
  84. // int mid = (L + R) >> 1, lans = -inf, rans = -inf;
  85. // if (begin <= mid) lans = queryRtoLsum(begin, end, lson);
  86. // if (end > mid) rans = queryRtoLsum(begin, end, rson);
  87. //
  88. // if (begin > mid) return rans;
  89. // if (end <= mid) return lans;
  90. // if (rans == end - mid) return rans + lans;
  91. // return rans;
  92. //}
  93. //int calc(int a) {
  94. // return queryLtoRsum(a, n, root) + queryRtoLsum(1, a, root);
  95. //}
  96. int query(int val, int L, int R, int cur) {
  97. // if (L == R) return L;
  98. pushDown(cur, R - L + );
  99. int mid = (L + R) >> ;
  100. if (sum[cur << ] >= val) return query(val, lson); //优先左孩子
  101. else if (LtoRsum[cur << | ] + RtoLsum[cur << ] >= val) return mid - RtoLsum[cur << ] + ;
  102. else return query(val, rson);
  103. }
  104. void work() {
  105. memset(add, -, sizeof add);
  106. cin >> n >> m;
  107. build(root);
  108. // int a = 7;
  109. // upDate(a, a, 0, root);
  110. // int ans = queryLtoRsum(a, n, root) + queryRtoLsum(1, a, root);
  111. // cout << ans - 1 << endl;
  112. for (int i = ; i <= m; ++i) {
  113. int flag, a, b;
  114. scanf("%d", &flag);
  115. if (flag == ) {
  116. scanf("%d", &a);
  117. if (sum[] < a) {
  118. printf("0\n");
  119. } else {
  120. int pos = query(a, root);
  121. printf("%d\n", pos);
  122. upDate(pos, pos + a - , , root);
  123. }
  124. } else {
  125. scanf("%d%d", &a, &b);
  126. upDate(a, min(a + b - , n), , root);
  127. }
  128. }
  129. }
  130.  
  131. int main() {
  132. #ifdef local
  133. freopen("data.txt","r",stdin);
  134. #endif
  135. work();
  136. return ;
  137. }

HDU 3974 Assign the task

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

给定一颗树,要求对这颗树进行染色,(类似思路)

操作

1、把节点x和其所有下属节点都染成y

2、查询x是什么颜色。

首先,对于一颗树,是不好处理的,要映射到一维数组,所以考虑dfs序,Lcur[i]和Rcur[i],表示这个节点在dfs的时候什么时候被访问到和什么时候退出访问。那么它映射到一维数组就是一个区间[Lcur[i], Rcur[i]],然后就是简单的线段树区间替换了

用sum[cur]表示这个节点所维护的区间的值,是否相同,不相同,就是-2,相同就是那个val,因为一开始什么任务都没有,所以就全部设置成-1,更新即可

bug点:记得所有区间都要用Lcur[]和Rcur[]表达,相当于映射到哪里去了。当时就是query的时候没用Lcur[a] 。一直wa

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. using namespace std;
  7. #define inf (0x3f3f3f3f)
  8. typedef long long int LL;
  9.  
  10. #include <iostream>
  11. #include <sstream>
  12. #include <vector>
  13. #include <set>
  14. #include <map>
  15. #include <queue>
  16. #include <string>
  17. #define root 1, n, 1
  18. #define lson L, mid, cur << 1
  19. #define rson mid + 1, R, cur << 1 | 1
  20. const int maxn = + ;
  21. int add[maxn << ];
  22. int sum[maxn << ];
  23. int Lcur[maxn];
  24. int Rcur[maxn];
  25. int first[maxn];
  26. bool in[maxn];
  27. struct node {
  28. int u, v, toNext;
  29. }e[maxn << ];
  30. int num, index;
  31. void addEdge(int u, int v) {
  32. ++num;
  33. e[num].u = u;
  34. e[num].v = v;
  35. e[num].toNext = first[u];
  36. first[u] = num;
  37. }
  38. void dfs(int cur) {
  39. Lcur[cur] = ++index;
  40. for (int i = first[cur]; i; i = e[i].toNext) {
  41. dfs(e[i].v);
  42. }
  43. Rcur[cur] = index;
  44. }
  45. void build(int L, int R, int cur) {
  46. sum[cur] = -;
  47. if (L == R) return;
  48. int mid = (L + R) >> ;
  49. build(lson);
  50. build(rson);
  51. }
  52. void pushDown(int cur) {
  53. if (add[cur] != -) {
  54. add[cur << ] = add[cur << | ] = add[cur];
  55. sum[cur] = sum[cur << ] = sum[cur << | ] = add[cur];
  56. add[cur] = -;
  57. }
  58. }
  59. void pushUp(int cur) {
  60. if (sum[cur << ] == sum[cur << | ]) sum[cur] = sum[cur << ];
  61. else sum[cur] = -;
  62. }
  63. void upDate(int begin, int end, int val, int L, int R, int cur) {
  64. if (L >= begin && R <= end) {
  65. sum[cur] = val;
  66. add[cur] = val;
  67. return;
  68. }
  69. pushDown(cur);
  70. int mid = (L + R) >> ;
  71. if (begin <= mid) upDate(begin, end, val, lson);
  72. if (end > mid) upDate(begin, end, val, rson);
  73. pushUp(cur);
  74. }
  75. int query(int pos, int L, int R, int cur) {
  76. if (sum[cur] != -) return sum[cur];
  77. pushDown(cur);
  78. int mid = (L + R) >> ;
  79. if (pos <= mid) return query(pos, lson);
  80. else return query(pos, rson);
  81. }
  82. int f;
  83. void work() {
  84. num = index = ;
  85. memset(first, , sizeof first);
  86. memset(in, , sizeof in);
  87. memset(add, -, sizeof add);
  88. printf("Case #%d:\n", ++f);
  89. int n;
  90. scanf("%d", &n);
  91. for (int i = ; i <= n - ; ++i) {
  92. int u, v;
  93. scanf("%d%d", &v, &u);
  94. addEdge(u, v);
  95. in[v] = ;
  96. }
  97. for (int i = ; i <= n; ++i) {
  98. if (in[i] == ) {
  99. dfs(i);
  100. break;
  101. }
  102. }
  103. // for (int i = 1; i <= n; ++i) {
  104. // printf("%d %d\n", L[i], R[i]);
  105. // }
  106. build(root);
  107. int m;
  108. scanf("%d", &m);
  109. for (int i = ; i <= m; ++i) {
  110. char op[];
  111. int a, b;
  112. scanf("%s", op);
  113. if (op[] == 'C') {
  114. scanf("%d", &a);
  115. printf("%d\n", query(Lcur[a], root));
  116. } else {
  117. scanf("%d%d", &a, &b);
  118. upDate(Lcur[a], Rcur[a], b, root);
  119. }
  120. }
  121. }
  122. int main() {
  123. #ifdef local
  124. freopen("data.txt","r",stdin);
  125. #endif
  126. int t;
  127. scanf("%d", &t);
  128. while (t--) work();
  129. return ;
  130. }

HDU 4578

Transformation

超级恶心的线段树

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

要维护操作区间增加,覆盖,乘上一个数字。然后查询区间1次方和,2次方和,3次方和。

首先可以考虑一下把1次方和,2次方和,3次方和分三个线段树来维护。

pushUp是最简单的,也就是左右儿子加起来。

但是每次增加一个数字时,2次方和会增加多少呢?

设本来是[a1, a2, a3......an],sum2 = a1^2 + a2^2 + ... + an^2。那么加上一个数字后,就会变成sum2 = (a1 + val)^2 + (a2 + val)^2 + .....+(an + val)^2。所以这样可以拆开来。变成本来的sum2 + 2 * val * (a1 + a2 + .... + an) + total * val * val。(total是区间大小)。所以这样就可以lazy--update了

三次方和同理。覆盖和乘上一个数字更加简单。

但是有问题,考虑下本来区间就已经需要加上一个数字的了(因为lazy--update的缘故,还没传递下去)。那么现在再在这个区间上乘上一个数字,那么你后来向下传递下去的add就应该是本来的val * add倍了。

(这就提示我们,在pushDown的时候,顺序是先pushdown相同,再乘法,再加法)

1、因为有相同的话,可以把乘法和加法都变成0了。

2、先传递乘法,免得传递加法后,再传递乘法再次把加法的add变成val * add倍

一定要注意细节,add操作那里,取模的时候一定要小心,看看有没地方没有及时取模,还有query的时候,左孩子+右孩子后,也是要去摸

可能要把val * val * val % MOD用个变量来保存一下,我不知道为什么不用变量保存会wa

还有long long int 确实比int快,可以把我的myTypec改成LL试一试

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. #define IOS ios::sync_with_stdio(false)
  7. using namespace std;
  8. #define inf (0x3f3f3f3f)
  9. typedef long long int LL;
  10.  
  11. #include <iostream>
  12. #include <sstream>
  13.  
  14. #define root 1, n, 1
  15. #define lson L, mid, cur << 1
  16. #define rson mid + 1, R, cur << 1 | 1
  17. typedef int myTypec;
  18. int n, m;
  19. const int maxn = + ;
  20. const int MOD = ;
  21. myTypec sum1[maxn << ], sum2[maxn << ], sum3[maxn << ];
  22. myTypec add[maxn << ], mult[maxn << ], same[maxn << ];
  23. void build(int L, int R, int cur) {
  24. sum1[cur] = sum2[cur] = sum3[cur] = ;
  25. add[cur] = mult[cur] = same[cur] = ;
  26. if (L == R) return;
  27. int mid = (L + R) >> ;
  28. build(lson);
  29. build(rson);
  30. }
  31. void pushUp(int cur) {
  32. sum1[cur] = (sum1[cur << ] + sum1[cur << | ]) % MOD;
  33. sum2[cur] = (sum2[cur << ] + sum2[cur << | ]) % MOD;
  34. sum3[cur] = (sum3[cur << ] + sum3[cur << | ]) % MOD;
  35. }
  36. myTypec sum11;
  37. myTypec sum22;
  38. myTypec sum33;
  39. void Toadd(int cur, int val, int total) {
  40. sum11 = sum1[cur];
  41. sum22 = sum2[cur];
  42.  
  43. sum1[cur] += (total * val) % MOD;
  44. sum1[cur] %= MOD;
  45.  
  46. myTypec temp = val * val % MOD;
  47. sum2[cur] += (( * val * sum11) % MOD + (total * temp) % MOD) %MOD;
  48. sum2[cur] %= MOD;
  49.  
  50. myTypec liu = temp;
  51. temp = temp * val % MOD;
  52. sum3[cur] += (( * sum22 * val) % MOD + ( * liu * sum11) % MOD + (total * temp) % MOD) % MOD;
  53. sum3[cur] %= MOD;
  54.  
  55. add[cur] += val;
  56. add[cur] %= MOD;
  57. }
  58. void ToMult(int cur, int val, int total) {
  59. sum11 = sum1[cur];
  60. sum22 = sum2[cur];
  61.  
  62. sum1[cur] *= val;
  63. sum1[cur] %= MOD;
  64.  
  65. myTypec temp = val * val % MOD;
  66. sum2[cur] *= temp;
  67. sum2[cur] %= MOD;
  68.  
  69. temp = temp * val % MOD;
  70. sum3[cur] *= temp;
  71. sum3[cur] %= MOD;
  72.  
  73. if (mult[cur]) {
  74. mult[cur] *= val;
  75. mult[cur] %= MOD;
  76. } else mult[cur] = val;
  77.  
  78. add[cur] = add[cur] * val % MOD;
  79. }
  80. void ToSame(int cur, int val, int total) {
  81. same[cur] = val;
  82. add[cur] = mult[cur] = ;
  83. sum1[cur] = total * val % MOD;
  84. myTypec temp = val * val % MOD;
  85. sum2[cur] = total * temp % MOD;
  86. temp = temp * val % MOD;
  87. sum3[cur] = total * temp % MOD;
  88. }
  89. void pushDown(int cur, int total) {
  90. if (same[cur]) {
  91. ToSame(cur << , same[cur], total - (total >> ));
  92. ToSame(cur << | , same[cur], total >> );
  93. same[cur] = ;
  94. }
  95. if (mult[cur]) {
  96. ToMult(cur << , mult[cur], total - (total >> ));
  97. ToMult(cur << | , mult[cur], total >> );
  98. mult[cur] = ;
  99. }
  100. if (add[cur]) {
  101. Toadd(cur << , add[cur], total - (total >> ));
  102. Toadd(cur << | , add[cur], total >> );
  103. add[cur] = ;
  104. }
  105. }
  106. void upDate(int begin, int end, int val, int L, int R, int cur, int flag) {
  107. if (L >= begin && R <= end) {
  108. if (flag == ) { //加上一个数
  109. Toadd(cur, val, R - L + );
  110. } else if (flag == ) { //乘上一个数
  111. ToMult(cur, val, R - L + );
  112. } else if (flag == ) {
  113. ToSame(cur, val, R - L + );
  114. }
  115. // while(1);
  116. return;
  117. }
  118. pushDown(cur, R - L + );
  119. int mid = (L + R) >> ;
  120. if (begin <= mid) upDate(begin, end, val, lson, flag);
  121. if (end > mid) upDate(begin, end, val, rson, flag);
  122. pushUp(cur);
  123. }
  124. myTypec query(int begin, int end, int L, int R, int cur, int p) {
  125. if (L >= begin && R <= end) {
  126. if (p == ) return sum1[cur];
  127. if (p == ) return sum2[cur];
  128. if (p == ) return sum3[cur];
  129. while();
  130. }
  131. pushDown(cur, R - L + );
  132. int mid = (L + R) >> ;
  133. myTypec ans = ;
  134. if (begin <= mid) {
  135. ans += query(begin, end, lson, p);
  136. ans %= MOD;
  137. }
  138. if (end > mid) {
  139. ans += query(begin, end, rson, p);
  140. ans %= MOD;
  141. }
  142. return ans % MOD;
  143. }
  144. void work() {
  145. build(root);
  146. for (int i = ; i <= m; ++i) {
  147. int flag, L, R, val;
  148. cin >> flag >> L >> R >> val;
  149. if (L > R) swap(L, R);
  150. if (flag != ) {
  151. upDate(L, R, val, root, flag);
  152. } else {
  153. cout << query(L, R, root, val) << endl;
  154. }
  155. }
  156. }
  157.  
  158. int main() {
  159. #ifdef local
  160. freopen("data.txt","r",stdin);
  161. #endif
  162. IOS;
  163. while (cin >> n >> m) {
  164. if (n == && m == ) break;
  165. work();
  166. }
  167. return ;
  168. }

HDU 4614  二分 + 线段树

Vases and Flowers

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

两种操作,

1、区间替换,输出成功替换的个数

2、输出从a开始,大小为b的空白区间(不一定要连续),输出起始位置和终止位置,然后把这段区间标记为已占据。

注意,如果从a开始没有空白区间,输出那段话,如果有,就覆盖min(区间大小, b),多余的b是扔掉的。

明显可以用线段树维护区间空白个数的值,1表示空白,0表示占据,因为这方便我lazy--update

然后每次询问有没b个空白区间,就是从[a, n - 1]中找有多少个空白区间,然后因为它要最靠近a的,b个

可以在[a, n - 1]中进行二分,先确定R,使得[a, R]的空白区间是b个的。然后因为a可能已经是被占据了的,所以继续二分,确定L

PS:那个"[pre]"是没用的,不用管

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. #define IOS ios::sync_with_stdio(false)
  7. using namespace std;
  8. #define inf (0x3f3f3f3f)
  9. typedef long long int LL;
  10.  
  11. #include <iostream>
  12. #include <sstream>
  13. #include <vector>
  14. #include <set>
  15. #include <map>
  16. #include <queue>
  17. #include <string>
  18. #define root 0, n - 1, 1
  19. #define lson L, mid, cur << 1
  20. #define rson mid + 1, R, cur << 1 | 1
  21. const int maxn = + ;
  22. int n, m;
  23. int sum[maxn << ], add[maxn << ];
  24. void build(int L, int R, int cur) {
  25. sum[cur] = R - L + ;
  26. add[cur] = -;
  27. if (L == R) return;
  28. int mid = (L + R) >> ;
  29. build(lson);
  30. build(rson);
  31. }
  32. void pushDown(int cur, int total) {
  33. if (add[cur] != -) {
  34. add[cur << ] = add[cur << | ] = add[cur];
  35. sum[cur << ] = (total - (total >> )) * add[cur];
  36. sum[cur << | ] = (total >> ) * add[cur];
  37. add[cur] = -;
  38. }
  39. }
  40. void pushUp(int cur) {
  41. sum[cur] = sum[cur << ] + sum[cur << | ];
  42. }
  43. void upDate(int begin, int end, int val, int L, int R, int cur) {
  44. if (L >= begin && R <= end) {
  45. sum[cur] = (R - L + ) * val;
  46. add[cur] = val;
  47. return;
  48. }
  49. pushDown(cur, R - L + );
  50. int mid = (L + R) >> ;
  51. if (begin <= mid) upDate(begin, end, val, lson);
  52. if (end > mid) upDate(begin, end, val, rson);
  53. pushUp(cur);
  54. }
  55. int query(int begin, int end, int L, int R, int cur) {
  56. if (L >= begin && R <= end) return sum[cur];
  57. pushDown(cur, R - L + );
  58. int mid = (L + R) >> ;
  59. int ans = ;
  60. if (begin <= mid) ans += query(begin, end, lson);
  61. if (end > mid) ans += query(begin, end, rson);
  62. return ans;
  63. }
  64. void bin_find(int a, int b, int toFindVal) { //a是起点[a, n - 1]
  65. int L = a, R = inf;
  66. int begin = a, end = n - ;
  67. while (begin <= end) {
  68. int mid = (begin + end) >> ;
  69. if (query(L, mid, root) >= toFindVal) {
  70. R = mid;
  71. end = mid - ;
  72. } else begin = mid + ;
  73. }
  74. begin = a;
  75. end = R;
  76. while (begin <= end) {
  77. int mid = (begin + end) >> ;
  78. if (query(mid, R, root) >= toFindVal) {
  79. L = mid;
  80. begin = mid + ;
  81. } else end = mid - ;
  82. }
  83. printf("%d %d\n", L, R);
  84. upDate(L, R, , root);
  85. }
  86. void work() {
  87. scanf("%d%d", &n, &m);
  88. build(root);
  89. for (int i = ; i <= m; ++i) {
  90. int flag, a, b;
  91. scanf("%d%d%d", &flag, &a, &b);
  92. if (flag == ) {
  93. int ans = query(a, n - , root);
  94. if (ans == ) {
  95. printf("Can not put any one.\n");
  96. } else {
  97. bin_find(a, b, min(ans, b)); //同时update了
  98. }
  99. } else {
  100. if (a > b) swap(a, b);
  101. int ans = b - a + - query(a, b, root);
  102. printf("%d\n", ans);
  103. upDate(a, b, , root);
  104. }
  105. }
  106. }
  107. int main() {
  108. #ifdef local
  109. freopen("data.txt","r",stdin);
  110. #endif
  111. int t;
  112. scanf("%d", &t);
  113. while (t--) {
  114. work();
  115. printf("\n");
  116. }
  117. return ;
  118. }

hdu 4553

约会安排

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

和  POJ 3667  Hotel 一样的。

维护两个线段树,NS的先从sumOne(就是屌丝的)去找。然后占据,占据的时候同时更新女神的。就这样。看看Hotel那题的思路,就知道了。

刚开始的时候pushDownTwo少了一句话。wa到我傻逼一样。。委屈啊。

然后从Hotel那题试出来是pushDownTwo错误了,也是一件快乐的事情~

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. #define IOS ios::sync_with_stdio(false)
  7. using namespace std;
  8. #define inf (0x3f3f3f3f)
  9. typedef long long int LL;
  10.  
  11. #include <iostream>
  12. #include <sstream>
  13. #include <vector>
  14. #include <set>
  15. #include <map>
  16. #include <queue>
  17. #include <string>
  18. #define root 1, n, 1
  19. #define lson L, mid, cur << 1
  20. #define rson mid + 1, R, cur << 1 | 1
  21. const int maxn = * + ;
  22. struct node {
  23. int LtoRsum, RtoLsum;
  24. int add;
  25. int sum;
  26. } sumOne[maxn << ], sumTwo[maxn << ];
  27. void build(int L, int R, int cur) {
  28. sumOne[cur].LtoRsum = sumOne[cur].RtoLsum = sumOne[cur].sum = R - L + ;
  29. sumTwo[cur].LtoRsum = sumTwo[cur].RtoLsum = sumTwo[cur].sum = R - L + ;
  30. sumOne[cur].add = sumTwo[cur].add = -;
  31. if (L == R) return;
  32. int mid = (L + R) >> ;
  33. build(lson);
  34. build(rson);
  35. }
  36. void pushDownOne(int cur, int total) {
  37. if (sumOne[cur].add != -) {
  38. sumOne[cur << ].add = sumOne[cur << | ].add = sumOne[cur].add;
  39. if (sumOne[cur].add) {
  40. sumOne[cur << ].LtoRsum = sumOne[cur << ].RtoLsum = sumOne[cur << ].sum = ;
  41. sumOne[cur << | ].LtoRsum = sumOne[cur << | ].RtoLsum = sumOne[cur << | ].sum = ;
  42. } else {
  43. sumOne[cur << ].LtoRsum = sumOne[cur << ].RtoLsum = sumOne[cur << ].sum = total - (total >> );
  44. sumOne[cur << | ].LtoRsum = sumOne[cur << | ].RtoLsum = sumOne[cur << | ].sum = (total >> );
  45. }
  46. sumOne[cur].add = -;
  47. }
  48. }
  49. void pushUpOne(int cur, int total) {
  50. sumOne[cur].LtoRsum = sumOne[cur << ].LtoRsum;
  51. sumOne[cur].RtoLsum = sumOne[cur << | ].RtoLsum;
  52. if (sumOne[cur].LtoRsum == (total - (total >> ))) sumOne[cur].LtoRsum += sumOne[cur << | ].LtoRsum;
  53. if (sumOne[cur].RtoLsum == (total >> )) sumOne[cur].RtoLsum += sumOne[cur << ].RtoLsum;
  54. sumOne[cur].sum = max(sumOne[cur << ].sum, sumOne[cur << | ].sum);
  55. sumOne[cur].sum = max(sumOne[cur].sum, sumOne[cur << ].RtoLsum + sumOne[cur << | ].LtoRsum);
  56. }
  57. void upDateOne(int begin, int end, int val, int L, int R, int cur) {
  58. if (L >= begin && R <= end) {
  59. if (val) {
  60. sumOne[cur].sum = sumOne[cur].LtoRsum = sumOne[cur].RtoLsum = ;
  61. } else sumOne[cur].sum = sumOne[cur].LtoRsum = sumOne[cur].RtoLsum = R - L + ;
  62. sumOne[cur].add = val;
  63. return;
  64. }
  65. pushDownOne(cur, R - L + );
  66. int mid = (R + L) >> ;
  67. if (begin <= mid) upDateOne(begin, end, val, lson);
  68. if (end > mid) upDateOne(begin, end, val, rson);
  69. pushUpOne(cur, R - L + );
  70. }
  71. int queryOne(int val, int L, int R, int cur) {
  72. if (L == R) return L;
  73. pushDownOne(cur, R - L + );
  74. // printf("%d %d %d***\n", L, R, sumOne[cur << 1].sum);
  75. int mid = (L + R) >> ;
  76. if (sumOne[cur << ].sum >= val) return queryOne(val, lson);
  77. else if (sumOne[cur << ].RtoLsum + sumOne[cur << | ].LtoRsum >= val) {
  78. // if (mid - sumOne[cur << 1].RtoLsum < 0) {
  79. //// printf("%d %d\n", mid, sumOne[cur << 1].RtoLsum);
  80. //// printf("%d %d\n", L, R);
  81. // printf("ff");
  82. // while(1);
  83. // }
  84. return mid - sumOne[cur << ].RtoLsum + ;
  85. }
  86. else return queryOne(val, rson);
  87. }
  88.  
  89. void pushDownTwo(int cur, int total) {
  90. if (sumTwo[cur].add != -) {
  91. sumTwo[cur << ].add = sumTwo[cur << | ].add = sumTwo[cur].add;
  92. if (sumTwo[cur].add) {
  93. sumTwo[cur << ].LtoRsum = sumTwo[cur << ].RtoLsum = sumTwo[cur << ].sum = ;
  94. sumTwo[cur << | ].LtoRsum = sumTwo[cur << | ].RtoLsum = sumTwo[cur << | ].sum = ;
  95. } else {
  96. sumTwo[cur << ].LtoRsum = sumTwo[cur << ].RtoLsum = sumTwo[cur << ].sum = total - (total >> );
  97. sumTwo[cur << | ].LtoRsum = sumTwo[cur << | ].RtoLsum = sumTwo[cur << | ].sum = (total >> );
  98. }
  99. sumTwo[cur].add = -;
  100. }
  101. }
  102. void pushUpTwo(int cur, int total) {
  103. sumTwo[cur].LtoRsum = sumTwo[cur << ].LtoRsum;
  104. sumTwo[cur].RtoLsum = sumTwo[cur << | ].RtoLsum;
  105. if (sumTwo[cur].LtoRsum == (total - (total >> ))) sumTwo[cur].LtoRsum += sumTwo[cur << | ].LtoRsum;
  106. if (sumTwo[cur].RtoLsum == (total >> )) sumTwo[cur].RtoLsum += sumTwo[cur << ].RtoLsum;
  107. sumTwo[cur].sum = max(sumTwo[cur << ].sum, sumTwo[cur << | ].sum);
  108. sumTwo[cur].sum = max(sumTwo[cur].sum, sumTwo[cur << ].RtoLsum + sumTwo[cur << | ].LtoRsum);
  109. }
  110. void upDateTwo(int begin, int end, int val, int L, int R, int cur) {
  111. if (L >= begin && R <= end) {
  112. if (val) {
  113. sumTwo[cur].sum = sumTwo[cur].LtoRsum = sumTwo[cur].RtoLsum = ;
  114. } else sumTwo[cur].sum = sumTwo[cur].LtoRsum = sumTwo[cur].RtoLsum = R - L + ;
  115. sumTwo[cur].add = val;
  116. return;
  117. }
  118. pushDownTwo(cur, R - L + );
  119. int mid = (L + R) >> ;
  120. if (begin <= mid) upDateTwo(begin, end, val, lson);
  121. if (end > mid) upDateTwo(begin, end, val, rson);
  122. pushUpTwo(cur, R - L + );
  123. }
  124. int queryTwo(int val, int L, int R, int cur) {
  125. if (L == R) return L;
  126. pushDownTwo(cur, R - L + );
  127. int mid = (L + R) >> ;
  128. if (sumTwo[cur << ].sum >= val) return queryTwo(val, lson);
  129. else if (sumTwo[cur << ].RtoLsum + sumTwo[cur << | ].LtoRsum >= val) return mid - sumTwo[cur << ].RtoLsum + ;
  130. else return queryTwo(val, rson);
  131. }
  132. int f;
  133. void work() {
  134. printf("Case %d:\n", ++f);
  135. int n, m;
  136. scanf("%d%d", &n, &m);
  137. // printf("%d %d\n", n, m);
  138. build(root);
  139. // upDateOne(1, 3, 1, root);
  140. // upDateOne(4, 5, 1, root);
  141. // upDateOne(1, 5, 0, root);
  142. // printf("%d\n", sumOne[1].sum);
  143. // printf("%d****\n", queryOne(5, root));
  144. for (int i = ; i <= m; ++i) {
  145. char op[];
  146. scanf("%s", op);
  147. if (op[] == 'S') {
  148. int L, R;
  149. scanf("%d%d", &L, &R);
  150. // if (L > R) swap(L, R);
  151. // printf("%d %d***\n", L, R);
  152. upDateOne(L, R, , root);
  153. upDateTwo(L, R, , root);
  154. printf("I am the hope of chinese chengxuyuan!!\n");
  155. } else if (op[] == 'D') { //屌丝
  156. int val;
  157. scanf("%d", &val);
  158. if (sumOne[].sum < val) {
  159. printf("fly with yourself\n");
  160. } else {
  161. int pos = queryOne(val, root);
  162. printf("%d,let's fly\n", pos);
  163. // printf("%d: %d %d\n", pos, val, sumOne[1].sum);
  164. upDateOne(pos, pos + val - , , root);
  165. }
  166. } else {
  167. int val;
  168. scanf("%d", &val);
  169. if (sumOne[].sum < val && sumTwo[].sum < val) {
  170. printf("wait for me\n");
  171. } else {
  172. if (sumOne[].sum >= val) {
  173. int pos = queryOne(val, root);
  174. printf("%d,don't put my gezi\n", pos);
  175. upDateOne(pos, pos + val - , , root);
  176. upDateTwo(pos, pos + val - , , root);
  177. } else {
  178. int pos = queryTwo(val, root);
  179. printf("%d,don't put my gezi\n", pos);
  180. upDateOne(pos, pos + val - , , root);
  181. upDateTwo(pos, pos + val - , , root);
  182. }
  183. }
  184. }
  185. }
  186. return;
  187. }
  188. int main() {
  189. #ifdef local
  190. freopen("data.txt","r",stdin);
  191. #endif
  192. int t;
  193. scanf("%d", &t);
  194. while (t--) {
  195. work();
  196. }
  197. return ;
  198. }

线段树 & 题目的更多相关文章

  1. 【ACM/ICPC2013】线段树题目集合(一)

    前言:前一段时间在网上找了一个线段树题目列表,我顺着做了一些,今天我把做过的整理一下.感觉自己对线段树了解的还不是很深,自己的算法能力还要加强.光练代码能力还是不够的,要多思考.向队友学习,向大牛学习 ...

  2. 嗯 第二道线段树题目 对左右节点和下标有了更深的理解 hdu1556

    Color the ball Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  3. Balanced Lineup(最简单的线段树题目)

    Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 33389   Accepted: 15665 Case Time Limit ...

  4. bzoj4196 [Noi2015]软件包管理器 树链剖分+线段树

    先把树剖分了(又是dfs1.dfs2),然后区间求和.区间覆盖即可 难得的1A好(shui)题 ——写了那么多题,终于有一道是1A的了,加上上一次连续交了几遍A的程序,我的状态莫名好看啊233 总结: ...

  5. POJ 2528 Mayor's posters (线段树)

    题目链接:http://poj.org/problem?id=2528 题目大意:有一个很上的面板, 往上面贴海报, 问最后最多有多少个海报没有被完全覆盖 解题思路:将贴海报倒着想, 对于每一张海报只 ...

  6. ACM: Copying Data 线段树-成段更新-解题报告

    Copying Data Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u Description W ...

  7. A线段树

    线段树专题 顾琪坤 1.简介: 打acm的时候,经常会碰到一类问题,比方给你n个数的序列,然后动态的更改某些数的值,然后又动态地询问某个区间的值的和或者其它乱七八糟的东西,对于单个更改或者询问,也许很 ...

  8. [cdoj843] 冰雪奇缘 (线段树+离散)

    [线段树 + 离散化] Description 艾莎女王又开始用冰雪魔法盖宫殿了. 她决定先造一堵墙,于是释放魔法让形为直角梯形的冰砖从天而降,定入冻土之中. 现在你将回答女王的询问:某段冻土上冰砖的 ...

  9. [kuangbin带你飞]专题七 线段树

            ID Origin Title 228 / 440 Problem A HDU 1166 敌兵布阵   207 / 438 Problem B HDU 1754 I Hate It   ...

随机推荐

  1. js 阿拉伯数字转转汉字

    js:(单纯的转汉字,没有个.十.千.万,待我日后完善) var number = 323413290907; var N = [ "零", "一", &quo ...

  2. 【HDU 3487】Play with Chain Splay

    题意 给定$n$个数序列,每次两个操作,将区间$[L,R]$拼接到去掉区间后的第$c$个数后,或者翻转$[L,R]$ Splay区间操作模板,对于区间提取操作,将$L-1$ Splay到根,再将$R+ ...

  3. (转)RTSP协议详解

    转自:https://www.cnblogs.com/lidabo/p/6553212.html RTSP简介     RTSP(Real Time Streaming Protocol)是由Real ...

  4. P2042 [NOI2005]维护数列[splay或非旋treap·毒瘤题]

    P2042 [NOI2005]维护数列 数列区间和,最大子列和(必须不为空),支持翻转.修改值.插入删除. 练码力的题,很毒瘤.个人因为太菜了,对splay极其生疏,犯了大量错误,在此记录,望以后一定 ...

  5. P4311 士兵占领[最大流]

    题目地址 有一个$M * N$的棋盘,有的格子是障碍.现在你要选择一些格子来放置一些士兵,一个格子里最多可以放置一个士兵,障碍格里不能放置士兵.我们称这些士兵占领了整个棋盘当满足第i行至少放置了$L_ ...

  6. ACM学习历程—HDU4720 Naive and Silly Muggles(计算几何)

    Description Three wizards are doing a experiment. To avoid from bothering, a special magic is set ar ...

  7. 五 Vue学习 首页学习 (上)

    首页:   http://localhost:8002/#/,  登录页面如下: index.js文件中如下的路由配置,转过去看login.vue是如何实现的. const routes = [ { ...

  8. c# list排序的实现方式

    实体类实现IComparable接口,而且必须实现CompareTo方法 实体类定义如下: class Info:IComparable { public int Id { get; set; } p ...

  9. MSSQl分布式查询(转)

    MSSQlServer所谓的分布式查询(Distributed Query)是能够访问存放在同一部计算机或不同计算机上的SQL Server或不同种类的数据源, 从概念上来说分布式查询与普通查询区别 ...

  10. skb详细解析【转】

    skb详细解析[转]    摘自:http://blog.chinaunix.net/uid-30035229-id-4883992.html     在自己的模块发送函数中,需要对skb进行重新构造 ...