当前位置:   article > 正文

【算法随笔:HDU 3333 Turing tree】(线段树 | 离线 | 离散化 | 贪心)

【算法随笔:HDU 3333 Turing tree】(线段树 | 离线 | 离散化 | 贪心)

 https://acm.hdu.edu.cn/showproblem.php?pid=3333icon-default.png?t=N7T8https://acm.hdu.edu.cn/showproblem.php?pid=3333https://vjudge.net.cn/problem/HDU-3333icon-default.png?t=N7T8https://vjudge.net.cn/problem/HDU-3333

题目很简单,给出长度为N的数组,Q次询问,每次给出区间[x, y), 问该区间内不同数字的和

思路:

预处理, 记录每个a[i]对应的最近相等值(max { k | k < i && a[k] == a[i])

for(int i {}; i < N; ++i) near[i] = last[a[i]], last[a[i]] = i;

只需在更新过程中,同时维护当前时刻,value of a[i]最后出现的下标即可

注意到这里的last[a[i]]有越界风险(max {a[i]} == INT_MAX)

需要离散化

枚举每个询问区间[x, y),对于a[i], 如果有near[i] < x, 意味着原数组最近一次出现value of a[i]不在该区间[x, y)内,也就意味着a[i]是区间中第一个出现的元素,可以被记录

由于每个区间可能有重叠,这时需要采用贪心思路和区间合并的思路,对区间左端点排序,依照次序依次处理询问区间,得到答案

具体看代码

  1. #include <array>
  2. #include <cstdio>
  3. #include <algorithm>
  4. constexpr auto __MAX__ { static_cast<int>(1e5) };
  5. //数组长度最大值
  6. constexpr auto __QUERIES__ { static_cast<int>(1e3) };
  7. //询问最大次数
  8. std::array<int, __MAX__ + 1> sequence {};
  9. std::array<int, __QUERIES__ + 1> x {};
  10. //询问区间左端点(闭)
  11. std::array<int, __QUERIES__ + 1> y {};
  12. //询问区间右端点(开)
  13. std::array<int, __QUERIES__ + 1> results {};
  14. //询问答案
  15. int N {};
  16. //数组长度
  17. int queries {};
  18. //询问次数
  19. std::array<int, __MAX__ + 1> uniques {};
  20. //用于离散化的辅助数组
  21. std::array<int, __MAX__ + 1> last{};
  22. //记录value: sequence[i] 最后一个出现(迭代过程)的下标
  23. std::array<int, __MAX__ + 1> left{};
  24. //记录与value: sequence[i] 相等的最近一次下标
  25. std::array<int, __MAX__ << 2 | 1> segments {};
  26. //线段树
  27. std::array<int, __QUERIES__ + 1> qtable {};
  28. //询问表排序
  29. std::array<int, __MAX__ + 1> stable {};
  30. //数组表排序
  31. constexpr int left(int index) noexcept { return x << 1; }
  32. constexpr int right(int index) noexcept { return x << 1 | 1; }
  33. //向上更新线段树,维护数组和
  34. constexpr update(int index) noexcept {
  35. segments[index] = std::plus<int>(segments[left(index)], segments[right(index)]);
  36. }
  37. int query(int first, int last) noexcept {
  38. return query(first, last, 0, N, 0);
  39. }
  40. //递归询问区间数组和
  41. int query(int first, int last, int current_first, int current_last, int index) noexcept {
  42. if(first <= current_first && last >= current_last) return segments[index];
  43. int middle { (current_first + current_last)/2 };
  44. return (
  45. first < middle ? query(first, last, current_first, middle, left(index)) : 0
  46. + last >= middle ? query(first, last, middle, current_last, right(index)) : 0 );
  47. }
  48. void change(int position, int value) noexcept {
  49. change(position, value, 0, N, 0);
  50. }
  51. //单点修改(加上固定常数),并且返回时维护线段树
  52. void change(int position, int value, int first, int last, int index) noexcept {
  53. if(first + 1 == last) return (void) (segments[index] += v);
  54. int middle { (first + last)/2 };
  55. if(position < middle) change(position, value, first, middle, left(index));
  56. else change(position, value, middle, last, right(index));
  57. update(index);
  58. }
  59. int main(void) {
  60. //读数组
  61. std::scanf("%d", &N);
  62. for(int i {}; i < N; (void) (uniques[i] = sequence[i ++]))
  63. std::scanf("%d", &sequence[i]);
  64. //读询问
  65. std::scanf("%d", &queries);
  66. for(int i {}; i < queries; ++i)
  67. std::scanf("%d%d", &x[i], &y[i]);
  68. //离散化
  69. std::sort(uniques.begin(), uniques.begin() + N);
  70. auto counter { static_cast<int>(
  71. std::distance(uniques.begin(),
  72. std::unique(uniques.begin(), uniques.begin() + N))) };
  73. for(int i {}; i < N; ++i)
  74. sequence[i] = static_cast<int>(
  75. std::distance(uniques.begin(),
  76. std::lower_bound(uniques.begin(), uniques.begin() + counter, sequence[i])));
  77. //初始化last数组
  78. std::fill_n(last.begin(), counter, -1);
  79. //更新left数组
  80. for(int i {}; i < N; ++i) {
  81. left[i] = last[sequence[i]];
  82. last[sequence[i]] = i;
  83. }
  84. /*
  85. ** 对询问和数组进行表排序,保证:
  86. ** 1: 询问区间左端点有序
  87. ** 2: 迭代过程中,最早出现的元素最先被遍历
  88. */
  89. for(int i {}; i < queries; ++i) qtable[i] = i;
  90. for(int i {}; i < N; ++i) stable[i] = i;
  91. std::sort(qtable.begin(), qtable.begin() + queries, [&](int i, int j) { return x[table[i]] < x[table[j]]; });
  92. std::sort(stable.begin(), stable.begin() + N, [&](int i, int j) { return left[stable[i]] < left[stable[j]]; });
  93. //离线处理询问
  94. int sentinel {};
  95. //遍历每个询问
  96. for(int i {}; i < queries; ++i) {
  97. //根据left数组,把在区间中的仅一次出现的元素,插入线段树
  98. while(sentinel < N && left[stable[sentinel]] < x[qtable[i]]) {
  99. change(stable[sentinel], uniques[sequence[stable[sentinel]]]);
  100. ++ sentinel;
  101. }
  102. //更新答案
  103. results[qtable[i]] = query(x[qtable[i], y[qtable[j]]);
  104. }
  105. //输出
  106. for(int i{}; i < queries; ++i) std::printf("%d%c", results[i], " \n"[! (i == queries)]);
  107. return 0;
  108. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/217988
推荐阅读
  

闽ICP备14008679号