维护区间的线段树

线段树主要就是在在PushUp和Query的时候注意怎么合并左右区间的信息就可以了。对于延迟标记的互相影响完全就是自己跟自己过不去,假如有多种延迟标记的话不妨在访问到一个区间时全部下推(只需要注意叶子层是不能下推的),从其他部分把常数补回来就可以了。

例1 维护加法和(修改:单点加值 询问:区间加法和)

  1. struct SegmentTree {
  2. #define ls (o<<1)
  3. #define rs (o<<1|1)
  4. static const int MAXN = 100000;
  5. ll a[MAXN + 5];
  6. ll st[(MAXN << 2) + 5];
  7. void PushUp(int o) {
  8. st[o] = st[ls] + st[rs];
  9. }
  10. void Build(int o, int l, int r) {
  11. if(l == r)
  12. st[o] = a[l];
  13. else {
  14. int m = l + r >> 1;
  15. Build(ls, l, m);
  16. Build(rs, m + 1, r);
  17. PushUp(o);
  18. }
  19. }
  20. void Update(int o, int l, int r, int p, ll v) {
  21. if(l == r) {
  22. st[o] += v;
  23. return;
  24. } else {
  25. int m = l + r >> 1;
  26. if(p <= m)
  27. Update(ls, l, m, p, v);
  28. if(p >= m + 1)
  29. Update(rs, m + 1, r, p, v);
  30. PushUp(o);
  31. }
  32. }
  33. ll Query(int o, int l, int r, int ql, int qr) {
  34. if(ql <= l && r <= qr) {
  35. return st[o];
  36. } else {
  37. int m = l + r >> 1;
  38. ll res = 0;
  39. if(ql <= m)
  40. res = res + Query(ls, l, m, ql, qr);
  41. if(qr >= m + 1)
  42. res = res + Query(rs, m + 1, r, ql, qr);
  43. return res;
  44. }
  45. }
  46. #undef ls
  47. #undef rs
  48. };

例2 维护加法和(修改:区间加值 询问:区间加法和)

  1. struct SegmentTree {
  2. #define ls (o<<1)
  3. #define rs (o<<1|1)
  4. static const int MAXN = 100000;
  5. ll a[MAXN + 5];
  6. ll st[(MAXN << 2) + 5], lazy[(MAXN << 2) + 5];
  7. void PushUp(int o) {
  8. st[o] = st[ls] + st[rs];
  9. }
  10. void PushDown(int o, int l, int r) {
  11. if(lazy[o]) {
  12. lazy[ls] += lazy[o];
  13. lazy[rs] += lazy[o];
  14. int m = l + r >> 1;
  15. st[ls] += lazy[o] * (m - l + 1);
  16. st[rs] += lazy[o] * (r - m);
  17. lazy[o] = 0;
  18. }
  19. }
  20. void Build(int o, int l, int r) {
  21. if(l == r)
  22. st[o] = a[l];
  23. else {
  24. int m = l + r >> 1;
  25. Build(ls, l, m);
  26. Build(rs, m + 1, r);
  27. PushUp(o);
  28. }
  29. lazy[o] = 0;
  30. }
  31. void Update(int o, int l, int r, int ql, int qr, ll v) {
  32. if(ql <= l && r <= qr) {
  33. lazy[o] += v;
  34. st[o] += v * (r - l + 1);
  35. return;
  36. } else {
  37. PushDown(o, l, r);
  38. int m = l + r >> 1;
  39. if(ql <= m)
  40. Update(ls, l, m, ql, qr, v);
  41. if(qr >= m + 1)
  42. Update(rs, m + 1, r, ql, qr, v);
  43. PushUp(o);
  44. }
  45. }
  46. ll Query(int o, int l, int r, int ql, int qr) {
  47. if(ql <= l && r <= qr) {
  48. return st[o];
  49. } else {
  50. PushDown(o, l, r);
  51. int m = l + r >> 1;
  52. ll res = 0;
  53. if(ql <= m)
  54. res = res + Query(ls, l, m, ql, qr);
  55. if(qr >= m + 1)
  56. res = res + Query(rs, m + 1, r, ql, qr);
  57. return res;
  58. }
  59. }
  60. #undef ls
  61. #undef rs
  62. };

例3 维护最大最小值(修改:区间加值 询问:区间最大最小值)

  1. struct SegmentTree {
  2. #define ls (o<<1)
  3. #define rs (o<<1|1)
  4. static const int MAXN = 1000000;
  5. static const int INF = 0x3f3f3f3f;
  6. int mi[(MAXN << 2) + 5];
  7. int ma[(MAXN << 2) + 5];
  8. int lz[(MAXN << 2) + 5];
  9. void PushUp(int o) {
  10. mi[o] = min(mi[ls], mi[rs]);
  11. ma[o] = max(ma[ls], ma[rs]);
  12. }
  13. void PushDown(int o, int l, int r) {
  14. if(lz[o]) {
  15. lz[ls] += lz[o];
  16. lz[rs] += lz[o];
  17. //int m = l + r >> 1;
  18. mi[ls] += lz[o];
  19. mi[rs] += lz[o];
  20. ma[ls] += lz[o];
  21. ma[rs] += lz[o];
  22. lz[o] = 0;
  23. }
  24. }
  25. void Build(int o, int l, int r) {
  26. if(l == r) {
  27. mi[o] = 0;
  28. ma[o] = 0;
  29. } else {
  30. int m = l + r >> 1;
  31. Build(ls, l, m);
  32. Build(rs, m + 1, r);
  33. PushUp(o);
  34. }
  35. lz[o] = 0;
  36. }
  37. void Update(int o, int l, int r, int ql, int qr, int v) {
  38. if(ql <= l && r <= qr) {
  39. lz[o] += v;
  40. mi[o] += v;
  41. ma[o] += v;
  42. } else {
  43. PushDown(o, l, r);
  44. int m = l + r >> 1;
  45. if(ql <= m)
  46. Update(ls, l, m, ql, qr, v);
  47. if(qr >= m + 1)
  48. Update(rs, m + 1, r, ql, qr, v);
  49. PushUp(o);
  50. }
  51. }
  52. int QueryMin(int o, int l, int r, int ql, int qr) {
  53. if(ql <= l && r <= qr) {
  54. return mi[o];
  55. } else {
  56. PushDown(o, l, r);
  57. int m = l + r >> 1;
  58. int res = INF;
  59. if(ql <= m)
  60. res = QueryMin(ls, l, m, ql, qr);
  61. if(qr >= m + 1)
  62. res = min(res, QueryMin(rs, m + 1, r, ql, qr));
  63. return res;
  64. }
  65. }
  66. int QueryMax(int o, int l, int r, int ql, int qr) {
  67. if(ql <= l && r <= qr) {
  68. return ma[o];
  69. } else {
  70. PushDown(o, l, r);
  71. int m = l + r >> 1;
  72. int res = -INF;
  73. if(ql <= m)
  74. res = QueryMax(ls, l, m, ql, qr);
  75. if(qr >= m + 1)
  76. res = max(res, QueryMax(rs, m + 1, r, ql, qr));
  77. return res;
  78. }
  79. }
  80. #undef ls
  81. #undef rs
  82. } st;

这种线段树可以简单拓展:加多一个标记,记录这个区间的最值出自哪个元素。尤其容易维护出最左侧/最右侧的最值。


维护值域的线段树(权值线段树)

需要先离线所有可能的取值,然后离散化到线段树可以接受的空间范围。每个节点存当前的值域的信息,最简单的应用是维护当前值域的元素共有多少个。那么可以在线段树上二分,返回当前线段树中的第k大。这种情形用于在某些情况下替代平衡树的功能,优点是常数相对平衡树而言很小,对于插入数据的顺序有要求,有时可能还要求离线。真正在线维护全树第k大的只有平衡树。

  1. struct SegmentTree {
  2. #define ls (o<<1)
  3. #define rs (o<<1|1)
  4. static const int MAXN = 100000;
  5. int cnt[(MAXN << 2) + 5];
  6. void PushUp(int o) {
  7. cnt[o] = cnt[ls] + cnt[rs];
  8. }
  9. void Build(int o, int l, int r) {
  10. if(l == r)
  11. cnt[o] = 0;
  12. else {
  13. int m = l + r >> 1;
  14. Build(ls, l, m);
  15. Build(rs, m + 1, r);
  16. PushUp(o);
  17. }
  18. }
  19. //修改值为p的元素的个数,增量为v,且不能为负
  20. void Update(int o, int l, int r, int p, int v) {
  21. if(l == r) {
  22. cnt[o] += v;
  23. if(cnt[o] < 0)
  24. cnt[o] = 0;
  25. return;
  26. } else {
  27. int m = l + r >> 1;
  28. if(p <= m)
  29. Update(ls, l, m, p, v);
  30. if(p >= m + 1)
  31. Update(rs, m + 1, r, p, v);
  32. PushUp(o);
  33. }
  34. }
  35. //查询<=x的元素的个数
  36. int GetRank(int o, int l, int r, int x) {
  37. if(r <= x) {
  38. return cnt[o];
  39. } else {
  40. int m = l + r >> 1;
  41. if(x <= m)
  42. return GetRank(ls, l, m, x);
  43. else
  44. return cnt[ls] + GetRank(rs, m + 1, r, x);
  45. }
  46. }
  47. //查询最小的x,使得<=x的元素个数>=rk(第rk小)
  48. int GetValue(int o, int l, int r, int rk) {
  49. if(l == r) {
  50. return l;
  51. } else {
  52. int m = l + r >> 1;
  53. if(cnt[ls] >= rk)
  54. return GetValue(ls, l, m, rk);
  55. else
  56. return GetValue(rs, m + 1, r, rk - cnt[ls]);
  57. }
  58. }
  59. #undef ls
  60. #undef rs
  61. } st;

注意:这里面传入的参数都应该是离散化之后的值。权值线段树不能用一次递归实现GetPrev()和GetNext(),需要通过给离散化的值做出一些修改,然后组合GetRank()和GetNext()才可以实现。优势在于代码短,常数小。

动态开点权值线段树

不再需要提前离散化了。

模板 - 数据结构 - 线段树/SegmentTree的更多相关文章

  1. 洛谷——P3373 【模板】线段树 2&& B 数据结构

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 线段树维护区间乘法 1.如何 ...

  2. 「模板」 线段树——区间乘 && 区间加 && 区间求和

    「模板」 线段树--区间乘 && 区间加 && 区间求和 原来的代码太恶心了,重贴一遍. #include <cstdio> int n,m; long l ...

  3. 线段树学习笔记(基础&进阶)(一) | P3372 【模板】线段树 1 题解

    什么是线段树 线段树是一棵二叉树,每个结点存储需维护的信息,一般用于处理区间最值.区间和等问题. 线段树的用处 对编号连续的一些点进行修改或者统计操作,修改和统计的复杂度都是 O(log n). 基础 ...

  4. 洛谷P3372 【模板】线段树 1

    P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷 ...

  5. 洛谷P3373 【模板】线段树 2

     P3373 [模板]线段树 2 47通过 186提交 题目提供者HansBug 标签 难度提高+/省选- 提交  讨论  题解 最新讨论 为啥WA(TAT) 题目描述 如题,已知一个数列,你需要进行 ...

  6. hdu 3074 Multiply game(模板级线段树)

    离机房关门还有十分钟,这点时间能干些什么?故作沉思地仰望星空,重新捋一下一天的学习进度,或者,砍掉一棵模板级线段树. 纯模板,就是把单点更新,区间求和改为单点更新,区间求积. 1A. #include ...

  7. 线段树练习 3&&P3372 【模板】线段树 1

    题目描述 Description 给你N个数,有两种操作: 1:给区间[a,b]的所有数增加X 2:询问区间[a,b]的数的和. 输入描述 Input Description 第一行一个正整数n,接下 ...

  8. Luogu3373【模板】线段树2

    P3373[模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行 ...

  9. 洛谷 P3373 【模板】线段树 2 解题报告

    P3373 [模板]线段树 2 题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上\(x\) 2.将某区间每一个数加上\(x\) 3.求出某区间每一个数的和 输入输出格式 ...

随机推荐

  1. 湖南师范大学计算机基础课网络教学平台 版本 V2.0(2017.9.18)

    湖南师范大学计算机基础课网络教学平台 版本 V2.0(2017.9.18) 开发环境: 开发工具:VS2013,数据库:Sqlserver2012 开发语言:Asp.net MVC5 ,界面UI:jq ...

  2. VS2017 配置 boost_1_70

    1. 下载与安装 1.1 安装方法1 (1) 下载 https://www.boost.org/ 或者使用 https://sourceforge.net/projects/boost/files/b ...

  3. 如何把前端用ajax发过来的图片传到node上,并且用node保存在oss图片服务器上?

    一:只上传一张图片 1.1:node需要安装的插件,先安好 npm install ali-oss uuid co --save A.ali-oss 用途:aliyun OSS(Object Stor ...

  4. 1+X证书学习日志——函数

    工具得特点: 1:重复性使用 2:隐藏内部原理(细节) 3:选择性应用 创建函数: 1:关键字 function 函数名称(){ } 2:字面量创建 var fn = function(){ } 3: ...

  5. Part_two:Redis之发布订阅

    Redis发布订阅 发布订阅的命令 PUBLISH channel msg 将信息 message 发送到指定的频道 channel SUBSCRIBE channel [channel ...] 订 ...

  6. Java System Reports

    You use Java System Reports as a problem detection and analysis tool to: ●      Monitor the AS Java ...

  7. 【iOS录音与播放】实现利用音频队列,通过缓存进行对声音的采集与播放

    都说iOS最恶心的部分是流媒体,其中恶心的恶心之处更在即时语音. 所以我们先不谈即时语音,研究一下,iOS中声音采集与播放的实现. 要在iOS设备上实现录音和播放功能,苹果提供了简单的做法,那就是利用 ...

  8. Jenkins 插件:Job Configuration History(记录job的历史更新记录)

    1. 添加插件   添加完成后,Jenkins,左下,多一个菜单栏 .可以查看,job的更新记录,见下图 .   如上,End再也不用担心,有同学乱改Job ,却不知道哪里被改的情况了. 注:1)这个 ...

  9. AspNetCore架构图

    asp,net,core  All-in-One App All-in-One applications N-Layer 典型的应用层 分层项目骨架 Clean Architecture Layers ...

  10. 《CoderXiaoban》第八次团队作业:Alpha冲刺 2

    项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 实验十二 团队作业8:软件测试与ALPHA冲刺 团队名称 Coderxiaoban团队 作业学习目标 (1)掌握软件测试基 ...