当前位置:   article > 正文

函数式线段树(区间数出现次数)

函数式线段树(区间数出现次数)

函数式线段树主要功能有区间 k 大值之类。

其核心思想为:在一个线段树上面利用原有的信息,每次只增加 log 级别的节点,就可以完成复制信息的任务。

这有什么用呢?假设你需要求区间 k 大值,你可以考虑对于每一个节点 i 建一颗线段树,所储存的为每个数在前 i 位上出现的次数,这样就可以在 log n 的时间内统计出一段数字在前 i 为上出现的次数。然后利用区间减法,就可以在 log n 时间内求出区间内数的出现次数前缀和为 k 的那一位,最后确定答案。

这是一道叫 lyp的题,其所求为区间内数的出现次数。代码是动态实现的:

  1. #include <cstdio>
  2. #include <cstdlib>
  3. #include <cstring>
  4. #include <algorithm>
  5. #define swap(a, b, t) ({t _ = (a); (a) = (b); (b) = _;})
  6. #define max(a, b) ({int _ = (a), __ = (b); _ > __ ? _ : __;})
  7. #define min(a, b) ({int _ = (a), __ = (b); _ < __ ? _ : __;})
  8. #define maxv 2000005
  9. #define maxn 100005
  10. int n, m, tot, k, ll, rr, ans, R = 100000;
  11. int a[maxn];
  12. struct da{int s; da * l, * r;} ve[maxv], * root[maxn];
  13. void build(da * & p, int l, int r)
  14. {
  15. p = ve + (++ tot);
  16. if (l < r) build(p->l, l, l + r >> 1), build(p->r, (l + r >> 1) + 1, r);
  17. }
  18. void revise(da * & p, da * q, int l, int r)
  19. {
  20. p = ve + (++ tot), * (p) = * (q), ++ p->s;
  21. if (l == r) return;
  22. if (k <= l + r >> 1) revise(p->l, q->l, l, l + r >> 1);
  23. else revise(p->r, q->r, (l + r >> 1) + 1, r);
  24. }
  25. int query(da * p, da * q, int l, int r)
  26. {
  27. if (ll <= l && r <= rr) return q->s - p->s;
  28. int ans = 0, m = l + r >> 1;
  29. if (ll <= m) ans += query(p->l, q->l, l, m);
  30. if (rr > m) ans += query(p->r, q->r, m + 1, r);
  31. return ans;
  32. }
  33. int main()
  34. {
  35. freopen("lyp.in", "r", stdin);
  36. freopen("lyp.out", "w", stdout);
  37. scanf("%d%d", & n, & m);
  38. build(root[0], 0, rr = R);
  39. for (int i = 1; i <= n; ++ i)
  40. {
  41. scanf("%d", a + i);
  42. k = a[i], revise(root[i], root[i - 1], 0, R);
  43. ll = k + 1, ans += query(root[0], root[i], 0, R);
  44. }
  45. printf("%d\n", ans);
  46. for (int p, q, l; m --; )
  47. {
  48. scanf("%d%d", & p, & q);
  49. if (l = ans, a[p] < q)
  50. {
  51. ll = a[p] + 1, rr = q, l -= query(root[0], root[p - 1], 0, R);
  52. ll = a[p], rr = q - 1, l += query(root[p], root[n], 0, R);
  53. }
  54. else if (q < a[p])
  55. {
  56. ll = q + 1, rr = a[p], l += query(root[0], root[p - 1], 0, R);
  57. ll = q, rr = a[p] - 1, l -= query(root[p], root[n], 0, R);
  58. }
  59. printf("%d\n", l);
  60. }
  61. return 0;
  62. }


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

闽ICP备14008679号