[关闭]
@ZCDHJ 2019-07-30T08:44:43.000000Z 字数 3110 阅读 476

HNOI2016 序列

未分类


使用莫队解决本题。考虑计算以每个数为终点的所有子串的最小值之和。 这里 代表前面第一个比 小的数字的位置。这个可以用 ST 表加二分做到 预处理。然后莫队转移区间时怎么计算右边新加入的数字造成的贡献?设当前q区间中最小数的位置为 ,权值为 。那么所有右端点为新加入的点,左端点在 左边(包括 )的子区间的z最小值都是 ,这部分区间的答案就是 。对于左端点在 右边的子区间, 即为答案。因为 中所有左端点超过 的也就是不需要的子区间的答案其实就是 ,画个图就很好理解。对于其他情况如删除也同理。注意在莫队转移的时候要先添加点再删除。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <cmath>
  5. #include <algorithm>
  6. typedef long long LL;
  7. #define int LL
  8. const int MAXN = 1e5;
  9. int n, m, blockSize, allL, allR, allAns;
  10. int a[MAXN | 1], pre[MAXN | 1], nxt[MAXN | 1], rmqTable[18][MAXN | 1], rmqTablePos[18][MAXN | 1], lg[MAXN | 1];
  11. int dp[2][MAXN | 1], ans[MAXN | 1];
  12. struct Query {
  13. int l, r, belong, id;
  14. Query() : l(0), r(0), belong(0), id(0) {}
  15. friend bool operator< (const Query &lhs, const Query &rhs) {
  16. return (lhs.belong < rhs.belong) || (lhs.belong == rhs.belong && lhs.r < rhs.r);
  17. }
  18. } que[MAXN | 1];
  19. inline int read() {
  20. register int x = 0, v = 1;
  21. register char ch = getchar();
  22. while (!isdigit(ch)) {
  23. if (ch == '-') v = -1;
  24. ch = getchar();
  25. }
  26. while (isdigit(ch)) {
  27. x = x * 10 + ch - '0';
  28. ch = getchar();
  29. }
  30. return x * v;
  31. }
  32. inline int calcMin(int l, int r) {
  33. return std::min(rmqTable[lg[r - l + 1]][l], rmqTable[lg[r - l + 1]][r - (1 << lg[r - l + 1]) + 1]);
  34. }
  35. inline int calcMinPos(int l, int r) {
  36. return rmqTable[lg[r - l + 1]][l] < rmqTable[lg[r - l + 1]][r - (1 << lg[r - l + 1]) + 1] ? rmqTablePos[lg[r - l + 1]][l] : rmqTablePos[lg[r - l + 1]][r - (1 << lg[r - l + 1]) + 1];
  37. }
  38. void getPreAndNxt() {
  39. for (int i = 1; i <= n; ++i) {
  40. int l = 1, r = i, mid;
  41. pre[i] = 0;
  42. while (l <= r) {
  43. mid = (l + r) >> 1;
  44. if (calcMin(mid, i) < a[i]) {
  45. pre[i] = mid;
  46. l = mid + 1;
  47. } else r = mid - 1;
  48. }
  49. }
  50. for (int i = n; i >= 1; --i) {
  51. int l = i, r = n, mid;
  52. nxt[i] = n + 1;
  53. while (l <= r) {
  54. mid = (l + r) >> 1;
  55. if (calcMin(i, mid) < a[i]) {
  56. nxt[i] = mid;
  57. r = mid - 1;
  58. } else l = mid + 1;
  59. }
  60. }
  61. for (int i = n; i >= 1; --i) dp[0][i] = dp[0][nxt[i]] + (nxt[i] - i) * a[i];
  62. for (int i = 1; i <= n; ++i) dp[1][i] = dp[1][pre[i]] + (i - pre[i]) * a[i];
  63. }
  64. void add(int x, int opt) {
  65. if (opt == 0) {
  66. int minVal = calcMin(allL, allR), minPos = calcMinPos(allL, allR);
  67. allAns += dp[0][x] - dp[0][minPos] + minVal * (allR - minPos + 1);
  68. } else {
  69. int minVal = calcMin(allL, allR), minPos = calcMinPos(allL, allR);
  70. allAns += dp[1][x] - dp[1][minPos] + minVal * (minPos - allL + 1);
  71. }
  72. }
  73. void del(int x, int opt) {
  74. if (opt == 0) {
  75. int minVal = calcMin(allL, allR), minPos = calcMinPos(allL, allR);
  76. allAns -= dp[0][x] - dp[0][minPos] + minVal * (allR - minPos + 1);
  77. } else {
  78. int minVal = calcMin(allL, allR), minPos = calcMinPos(allL, allR);
  79. allAns -= dp[1][x] - dp[1][minPos] + minVal * (minPos - allL + 1);
  80. }
  81. }
  82. signed main() {
  83. n = read();
  84. m = read();
  85. blockSize = sqrt(n);
  86. memset(rmqTable, 0x3f, sizeof(rmqTable));
  87. for (int i = 1; i <= n; ++i) a[i] = read(), rmqTable[0][i] = a[i], rmqTablePos[0][i] = i;
  88. for (int i = 1; i < 18; ++i) {
  89. for (int j = 1; j + (1 << i) - 1 <= n; ++j) {
  90. if (rmqTable[i - 1][j] < rmqTable[i - 1][j + (1 << (i - 1))]) {
  91. rmqTable[i][j] = rmqTable[i - 1][j];
  92. rmqTablePos[i][j] = rmqTablePos[i - 1][j];
  93. } else {
  94. rmqTable[i][j] = rmqTable[i - 1][j + (1 << (i - 1))];
  95. rmqTablePos[i][j] = rmqTablePos[i - 1][j + (1 << (i - 1))];
  96. }
  97. }
  98. }
  99. lg[1] = 0;
  100. for (int i = 2; i <= n; ++i) lg[i] = lg[i >> 1] + 1;
  101. getPreAndNxt();
  102. for (int i = 1; i <= m; ++i) {
  103. que[i].l = read();
  104. que[i].r = read();
  105. que[i].id = i;
  106. que[i].belong = (que[i].l - 1) / blockSize + 1;
  107. }
  108. std::sort(que + 1, que + 1 + m);
  109. int &l = allL, &r = allR;
  110. l = 1;
  111. r = 1;
  112. allAns = a[1];
  113. for (int i = 1; i <= m; ++i) {
  114. while (l > que[i].l) add(--l, 0);
  115. while (r < que[i].r) add(++r, 1);
  116. while (l < que[i].l) del(l, 0), ++l;
  117. while (r > que[i].r) del(r, 1), --r;
  118. ans[que[i].id] = allAns;
  119. }
  120. for (int i = 1; i <= m; ++i) printf("%lld\n", ans[i]);
  121. return 0;
  122. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注