线段树(ALGO-8重刷)

  1. #include <iostream>
  2. #define max(a,b) a > b ? a : b;
  3. using namespace std;
  4. const int MAXN = 1e2 + 1;
  5. int num = 0;
  6. /*线段树元素结构体*/
  7. struct NODE {
  8. int l;
  9. int r;
  10. int maxValue;
  11. int sum;
  12. }node[MAXN];
  13. /*初始化线段树*/
  14. void init(int i,int l,int r) {
  15. node[i].l = l;
  16. node[i].r = r;
  17. node[i].maxValue = 0;
  18. node[i].sum = 0;
  19. num++;
  20. if (node[i].l != node[i].r) {
  21. int mid = (l + r) / 2;
  22. init(2 * i,l, mid);
  23. init(2 * i + 1,mid + 1, r);
  24. }
  25. }
  26. /*插入线段树元素*/
  27. void insert(int i,int pos,int value) {
  28. if (node[i].l == node[i].r) { //错误五:“node[i].l = node[i].r” 判断条件错误,排查费时
  29. node[i].maxValue = value;
  30. node[i].sum = value;
  31. return; //错误一:遗漏return
  32. }
  33. int mid = (node[i].l + node[i].r) / 2;
  34. if (pos <= mid) insert(2 * i, pos, value);
  35. else insert(2 * i + 1, pos, value);
  36. /*同时初始化最大权值和总权值*/
  37. node[i].maxValue = max(node[2 * i].maxValue, node[2 * i + 1].maxValue);
  38. node[i].sum = node[2 * i].sum + node[2 * i + 1].sum;
  39. }
  40. /*查找范围内元素个体最大权值*/
  41. int search_max(int i, int x, int y) {
  42. if (node[i].l == x && node[i].r == y) { //错误三:node[i].l == node[i].r 条件判断错误
  43. return node[i].maxValue;
  44. }
  45. int mid = (node[i].l + node[i].r) / 2;
  46. if (y <= mid) return search_max(2 * i, x, y); //错误二:还是遗漏return
  47. else if (x > mid) return search_max(2 * i + 1, x, y);
  48. else {
  49. return max(search_max(2 * i, x, mid), search_max(2 * i + 1, mid + 1, y));
  50. }
  51. }
  52. /*查找范围内元素的权值和*/
  53. int search_sum(int i, int x, int y) {
  54. if (x == node[i].l && y == node[i].r) { //错误四:还是 node[i].l == node[i].r 条件判断错误
  55. return node[i].sum;
  56. }
  57. int mid = (node[i].l + node[i].r) / 2;
  58. if (y <= mid) return search_sum(2 * i, x, y);
  59. else if (x > mid) return search_sum(2 * i + 1, x, y);
  60. else {
  61. return search_sum(2 * i, x, mid) + search_sum(2 * i + 1, mid + 1, y);
  62. }
  63. }
  64. int main() {
  65. int n, m;
  66. cin >> n >> m;
  67. /*初始化*/
  68. init(1,1,n);
  69. /*看树*/
  70. cout << "show tree after init" << endl;
  71. int count = 1;
  72. for (int i = 1; i <= num; i++) {
  73. if (i >= pow(2, count)) {
  74. cout << endl;
  75. count++;
  76. }
  77. cout << "( " << node[i].l << ',' << node[i].r << " )";
  78. }
  79. cout << endl;
  80. /*插入*/
  81. int value;
  82. for (int i = 1; i <= n; i++) {
  83. cin >> value;
  84. insert(1, i, value);
  85. }
  86. /*再看树*/
  87. cout << "show tree after insert" << endl;
  88. count = 1;
  89. for (int i = 1; i <= num; i++) {
  90. if (i >= pow(2, count)) {
  91. cout << endl;
  92. count++;
  93. }
  94. cout << "( max:" << search_max(i,node[i].l,node[i].r) <<" ; sum:"
  95. << search_sum(i, node[i].l, node[i].r) << " )";
  96. }
  97. cout << endl;
  98. /*题目要求*/
  99. for (int i = 1; i <= m; i++) {
  100. int p, x, y;
  101. cin >> p >> x >> y;
  102. if (p == 1) insert(1, x, y);
  103. if (p == 2) cout << "sum = "<< search_sum(1, x, y) << endl;
  104. if (p == 3) cout << "max = "<< search_max(1, x, y) << endl;
  105. }
  106. return 0;
  107. }
  108. /*
  109. 4 3
  110. 1 2 3 4
  111. 2 1 3
  112. 1 4 3
  113. 3 1 4*/

线段树提升,懒惰标记

  1. #include <iostream>
  2. #include <cmath>
  3. using namespace std;
  4. const int MAXN = 1e2 + 1;
  5. int num = 0;
  6. struct NODE {
  7. int l;
  8. int r;
  9. int sum;
  10. int tag; //懒惰标记
  11. }node[MAXN];
  12. void init(int i, int left, int right); //初始化线段树
  13. void chahgeRespectively(int i, int pos, int value); //单点更新(错误1)
  14. void changeSegment(int i, int x, int y, int value); //区间更新(错误5)
  15. int findSum(int i, int x, int y); //查询区间内权值总和(错误2,4,6)
  16. void pushDown(int i); //下推标记(错误3)
  17. void update(int i); //节点递归更新
  18. void showTree(); //看树
  19. int main() {
  20. int n, x, y, t, pos;
  21. cin >> x >> y;
  22. init(1, x, y);
  23. showTree(); //showTree
  24. /*单点更新*/
  25. cin >> n;
  26. for (int i = 0; i < n; i++) {
  27. cin >> pos >> t;
  28. chahgeRespectively(1, pos, t);
  29. }
  30. showTree(); //showTree
  31. /*区间更新测试*/
  32. changeSegment(1, 1, 3, 1);
  33. showTree(); //showTree
  34. changeSegment(1, 2, 4, 2);
  35. showTree(); //showTree
  36. /*查询函数测试*/
  37. cout << "test F_findSum:" << endl;
  38. showTree();
  39. cout<<findSum(1, 2, 4);
  40. return 0;
  41. }
  42. /*初始化结点*/
  43. void init(int i, int left, int right) {
  44. node[i].l = left;
  45. node[i].r = right;
  46. node[i].sum = 0;
  47. node[i].tag = 0;
  48. num++;
  49. if (node[i].l != node[i].r) {
  50. int mid = (node[i].l + node[i].r) / 2;
  51. init(2 * i, left, mid);
  52. init(2 * i + 1, mid + 1, right);
  53. }
  54. }
  55. /*节点递归更新*/
  56. void update(int i) {
  57. node[i].sum = node[2 * i].sum + node[2 * i + 1].sum;
  58. return;
  59. }
  60. /*下推一次懒惰标记*/
  61. void pushDown(int i) {
  62. cout << endl << "i = " << i << endl;
  63. if (node[i].l == node[i].r) //错误三:“叶节点无需操作”,部分情况下节点tag要清零
  64. {
  65. node[i].tag = 0; //即使这次叶节点tag不清零答案没影响sum
  66. showTree();
  67. return;
  68. }
  69. /*更新到左右子节点,清除自身tag*/
  70. node[2 * i].sum += (node[2 * i].r - node[2 * i].l + 1) * node[i].tag;
  71. node[2 * i + 1].sum += (node[2 * i + 1].r - node[2 * i + 1].l + 1) * node[i].tag;
  72. node[2 * i].tag += node[i].tag;
  73. node[2 * i + 1].tag += node[i].tag;
  74. node[i].tag = 0;
  75. showTree();
  76. return;
  77. }
  78. /*单点更新*/
  79. void chahgeRespectively(int i,int pos,int value) {
  80. if (node[i].l == node[i].r) {
  81. node[i].sum = value;
  82. return; //错误一:再次漏了return
  83. }
  84. int mid = (node[i].l + node[i].r) / 2;
  85. if (pos <= mid) { chahgeRespectively(2 * i, pos, value); }
  86. if (pos > mid) { chahgeRespectively(2 * i + 1, pos, value); }
  87. update(i);
  88. }
  89. /*区间更新*/
  90. void changeSegment(int i, int x, int y, int value) {
  91. if (node[i].tag) pushDown(i); //如果已经有标记,下推标记
  92. if (node[i].l == x && node[i].r == y) { //正中靶心,信息只更新到该节点,并打上标记
  93. node[i].sum += (node[i].r - node[i].l + 1) * value;
  94. node[i].tag += value;
  95. return;
  96. }
  97. int mid = (node[i].l + node[i].r) / 2;
  98. if (y <= mid) {
  99. changeSegment(2 * i, x, y, value);
  100. }
  101. else if (x > mid) { //错误五:同错误四,else if (x >= mid)找区间判断条件错误
  102. changeSegment(2 * i + 1, x, y, value);
  103. }
  104. else {
  105. changeSegment(2 * i, x, mid, value);
  106. changeSegment(2 * i + 1, mid + 1, y, value);
  107. }
  108. update(i);
  109. }
  110. /*查询区间内权值总和*/
  111. int findSum(int i, int x, int y) {
  112. if (node[i].tag) pushDown(i); //查询节点有标记,下推标记
  113. if (node[i].l == x && node[i].r == y) { //正中靶心
  114. return node[i].sum;
  115. }
  116. int mid = (node[i].l + node[i].r) / 2;
  117. if (y <= mid) return findSum(2 * i, x, y); //错误二:if (y <= node[i].l) 条件写错
  118. else if(x > mid) return findSum(2 * i + 1, x, y); //错误四:else if(x >= mid) 条件写错
  119. else return findSum(2 * i, x, mid) + findSum(2 * i + 1, mid + 1, y); //错误六:引用范围错误,压根没用到mid
  120. }
  121. /*查看线段树*/
  122. void showTree() {
  123. cout << "show tree below" << endl;
  124. int count = 1;
  125. for (int i = 1; i <= num; i++) {
  126. if (i >= pow(2, count)) {
  127. cout << endl;
  128. count++;
  129. }
  130. cout << "( " << node[i].l << ',' << node[i].r <<",sum:"<<node[i].sum<<",tag:"<<node[i].tag<< " )";
  131. }
  132. cout <<endl<<"Dode"<<endl;
  133. }
  134. /*
  135. 1 5
  136. 5
  137. 1 1
  138. 2 2
  139. 3 3
  140. 4 4
  141. 5 5*/

repeat 1

  • 重复犯了上次的两个错误,并犯了两个新错误

    1. void changeSegment(int i, int x, int y, int value) {
    2. if (node[i].tag) pushDown(i); //有tag,下推一次
    3. if (x == node[i].l && node[i].r == y) {
    4. node[i].sum += (node[i].r - node[i].l + 1) * value;
    5. node[i].tag = value;
    6. return; //(新)错误三:这次区间更新没有加return
    7. }
    8. int mid = (node[i].l + node[i].r) / 2;
    9. if (y <= mid) changeSegment(2 * i, x, y, value); //错误一:y <= node[i].l 这种重复性错误
    10. else if (x > mid) changeSegment(2 * i + 1, x, y, value); //能不能长点脑子.jpg
    11. else {
    12. changeSegment(2 * i, x, mid, value);
    13. changeSegment(2 * i + 1, mid + 1, y, value);
    14. }
    15. update(i);
    16. }
    17. void pushDown(int i) {
    18. cout << endl << "i = " << i << endl;
    19. if (node[i].l == node[i].r) {
    20. node[i].tag = 0;
    21. showTree();
    22. return;
    23. }
    24. node[2 * i].sum += (node[2 * i].r - node[2 * i].l + 1) * node[i].tag; //(新)错误四:“sum =”错了,是sum +=
    25. node[2 * i + 1].sum += (node[2 * i + 1].r - node[2 * i + 1].l + 1) * node[i].tag;
    26. node[2 * i].tag += node[i].tag;
    27. node[2 * i + 1].tag += node[i].tag;
    28. node[i].tag = 0; //错误二,更新左右子节点后,没有清除自身tag
    29. showTree();
    30. }

    洛谷线段树1

  • 建树插入一气呵成 ```cpp

    include

    include

    using namespace std; const int MAXN = 100010; int n, m; struct NODE { int l; int r; long long tag; long long sum; }node[4*MAXN+2]; int a[MAXN];

void built(int i,int left,int right) { node[i].l = left; node[i].r = right; if (node[i].l == node[i].r) { node[i].sum = a[left]; return; } int mid = (left + right) / 2; built(2 i, left, mid); built(2 i + 1, mid + 1, right); node[i].sum = node[2 i].sum + node[2 i + 1].sum; } void pushDown(int i) { if (node[i].l == node[i].r) { return; } node[2 i].sum += (node[2 i].r - node[2 i].l + 1) node[i].tag; node[2 i + 1].sum += (node[2 i + 1].r - node[2 i + 1].l + 1) node[i].tag; node[2 i].tag += node[i].tag; node[2 i + 1].tag += node[i].tag; node[i].tag = 0; } /chanfeSegment/ void addSegment(int i, int x, int y, int value) { if (x <= node[i].l && node[i].r <= y) { node[i].sum += (long long)(node[i].r - node[i].l + 1) value; node[i].tag += value; return;
} if (node[i].tag) pushDown(i); int mid = (node[i].l + node[i].r) / 2; if(x <= mid) addSegment(2
i, x, y, value); if(y > mid) addSegment(2 i + 1, x, y, value); node[i].sum = node[2 i].sum + node[2 i + 1].sum;
} /
findSum/ long long findSum(int i, int x, int y) { if (node[i].tag) pushDown(i); if (node[i].l == x && node[i].r == y) return node[i].sum; int mid = (node[i].l + node[i].r) / 2; if (y <= mid) return findSum(2 i, x, y); else if(x > mid) return findSum(2 i + 1, x, y); else return findSum(2 i, x, mid) + findSum(2 * i + 1, mid + 1, y); } int main() { cin >> n >> m; for (int i = 1; i <= n; i++) { scanf(“%d”, &a[i]); } built(1, 1, n); int p, x, y, k; for (int i = 1; i <= m; i++) { //cin >> p; scanf(“%d”, &p); if (p == 1) { //cin >> x >> y >> k; scanf(“%d%d%d”, &x,&y,&k); addSegment(1, x, y, k); } else if (p == 2) { //cin >> x >> y; scanf(“%d%d”, &x,&y); cout << findSum(1, x, y) << endl; } } }

  1. <a name="qPomY"></a>
  2. ## 约瑟夫问题
  3. - 数学模拟
  4. ```cpp
  5. #include<cstdio>
  6. #include <iostream>
  7. using namespace std;
  8. int i, finds, k, m, begins;
  9. int check(int remain)
  10. {
  11. cout << "b = " << begins << ' ' << "m = " << m <<" remain = "<< remain << ' ';
  12. int result = (begins + m - 1) % remain;
  13. cout << result << ' ' << endl;
  14. if (result >= k) {//判断出列的那个人
  15. begins = result;
  16. return 1;
  17. }
  18. else { return 0; }
  19. }
  20. int main() {
  21. cin >> k;
  22. m = k;
  23. while (!finds)
  24. {
  25. cout <<endl<< "m = " << m << endl;
  26. finds = 1; begins = 0;//设置第一个
  27. for (i = 0; i < k; i++)
  28. {
  29. if (!check(2 * k - i))//如果判断好,就可以退出了……
  30. {
  31. finds = 0; break;
  32. }
  33. }
  34. m++;
  35. }
  36. cout<<m-1;//多加了一个,减回去
  37. return 0;
  38. }
  • 数组模拟
  • 迭代器模拟

最长公共子序列LCS

  • 处理好f[][]和s[]的坐标 ```cpp

    include

    include

    using namespace std; const int MAXN = 1e2 + 10; char s1[MAXN]; char s2[MAXN]; int f[MAXN][MAXN]; int m, n;

void LCS(int i, int j) { if (i == 0 || j == 0) return; //错误1:if (i == 0 && j == 0) if (s1[i-1] == s2[j-1]) { //错误2:if (s1[i] == s2[j]) LCS(i - 1, j - 1); cout << s1[i-1]; //错误3:cout << s1[i]; } else if (f[i][j - 1] > f[i - 1][j]) {
LCS(i, j - 1); } else { LCS(i - 1, j); } } int main() { gets_s(s1); gets_s(s2); m = strlen(s1); n = strlen(s2); for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (s1[i - 1] == s2[j - 1]) f[i][j] = 1 + f[i - 1][j - 1];
else f[i][j] = max(f[i][j - 1], f[i - 1][j]); } } cout << “LCS长度为:” << f[m][n] << endl; LCS(m, n);

  1. return 0;

} / algorithms alchemist 5 alhms/ ```