线段树 区间查询 单点修改

算法思想

这个算法是用于数组的查询和修改

可以高效的进行查询修改

但是会增加内存的使用

本质上是一种 空间换时间 的算法

这个算法把一串数组无限二分

直到分的只剩下一个数据

将每一段看成一个节点

这样就组成了一个树形结构

故名 线段树

代码实现

实现这个代码一共分三个步骤:

建树 查询 修改

这里先把变量含义解释一遍:

  1. #define maxn 1000010
  2. #define mid ((l+r)>>1)
  3. #define li i<<1
  4. #define ri 1+(i<<1)
  5. /*
  6. mid 线段中间节点的小标
  7. li i线段的左子树
  8. ri i线段的右子树
  9. */
  10. int n,val[maxn];
  11. /*
  12. n 数组的长度
  13. val 数组的值
  14. */
  15. struct Node{
  16. int l,r,sum;
  17. }tree[maxn];
  18. /*
  19. tree 即这个树形结构
  20. tree[i].l i线段的左端
  21. tree[i].r i线段的右端
  22. tree[i].sum i线段的所有节点的权值和
  23. */

建树

  1. void build(int i,int l,int r){
  2. tree[i].l = l;
  3. tree[i].r = r;
  4. if(l == r){
  5. tree[i].sum = val[l];
  6. return ;
  7. }
  8. build(li,l,mid);
  9. build(ri,mid+1,r);
  10. tree[i].sum = tree[li].sum + tree[ri].sum;
  11. return ;
  12. }

欲建树 先分步

我们只要处理好每个节点的三个值(l,r,sum)

这棵树自然也就建好了

l,r直接赋值即可

如果 if(l == r)

则说明这个节点已经无法再二分了

那么就把 \(val\) 的值直接赋给 \(sum\)

并且要记得 return ;

若 \(l != r\)

那就继续二分建子树

然后再把两个子树的值加起来即为自己的 \(sum\)

查询

  1. int search(int i,int l,int r){
  2. if(l <= tree[i].l && tree[i].r <= r)
  3. return tree[i].sum;
  4. if(tree[i].r < l || r < tree[i].l)
  5. return 0;
  6. int ans = 0;
  7. if(tree[li].r >= l) ans += search(li,l,r);
  8. if(tree[ri].l <= r) ans += search(ri,l,r);
  9. return ans;
  10. }

这步的主要思想是能大块就返回大块的值

不能再二分给儿子线段处理

由于已经把数组分得很细

因此不存在查询边界在线段中却无法二分的情况

  • \(l <= tree[i].l\) && \(tree[i].r <= r\)

这说明线段已经完全包裹在区间内(就和第二根绿色线段一样)

直接返回这个线段的值即可

  • \(tree[i].r < l\) \(||\) \(r < tree[i].l\)

这说明线段完全不在取值区间内

那就返回0

  • \(tree[li].r >= l\)

这说明有区间一部分在左子线段上

那就二分进行搜索

然后返回搜好的值

  • \(tree[ri].l <= r\)

和上面同理

有区间一部分在右子线段上

修改

  1. void add(int i,int dis,int k){
  2. if(tree[i].l == tree[i].r){
  3. tree[i].sum += k;
  4. return ;
  5. }
  6. if(dis <= tree[li].r)
  7. add(li,dis,k);
  8. else
  9. add(ri,dis,k);
  10. tree[i].sum = tree[li].sum + tree[ri].sum;
  11. return ;
  12. }

修改我自身感觉和建树有点相像

就是改变一个节点的值然后再将涉及到这个节点的线段重新建树

  • \(tree[i].l == tree[i].r\)

这代表已经找到了这个节点

那就把这个点的值修改掉

  • \(dis <= tree[li].r\)

如果在线段里

那就继续找

  • \(tree[i].sum = tree[li].sum + tree[ri].sum;\)

更新线段的值

线段数 区间修改 单点查询

Code

  1. #include<bits/stdc++.h>
  2. #define maxn 1000010
  3. #define mid ((l+r)>>1)
  4. #define li i<<1
  5. #define ri 1+(i<<1)
  6. using namespace std;
  7. int n,val[maxn];
  8. struct Node{
  9. int l,r,sum;
  10. }tree[maxn];
  11. void Read(){
  12. cin >> n;
  13. for(int i = 1;i <= n;i++)cin >> val[i];
  14. }
  15. void build(int i,int l,int r){
  16. tree[i].l = l;
  17. tree[i].r = r;
  18. if(l == r){
  19. tree[i].sum = val[l];
  20. return ;
  21. }
  22. build(li,l,mid);
  23. build(ri,mid+1,r);
  24. tree[i].sum = tree[li].sum + tree[ri].sum;
  25. return ;
  26. }
  27. int search(int i,int l,int r){
  28. if(l <= tree[i].l && tree[i].r <= r)
  29. return tree[i].sum;
  30. if(tree[i].r < l || r < tree[i].l)
  31. return 0;
  32. int ans = 0;
  33. if(tree[li].r >= l) ans += search(li,l,r);
  34. if(tree[ri].l <= r) ans += search(ri,l,r);
  35. return ans;
  36. }
  37. void add(int i,int dis,int k){
  38. if(tree[i].l == tree[i].r){
  39. tree[i].sum += k;
  40. return ;
  41. }
  42. if(dis <= tree[li].r)
  43. add(li,dis,k);
  44. else
  45. add(ri,dis,k);
  46. tree[i].sum = tree[li].sum + tree[ri].sum;
  47. return ;
  48. }
  49. void interaction(){
  50. while(1){
  51. int tot;
  52. cin >> tot;
  53. if(tot == 1){
  54. int l,r;
  55. cin >> l >> r;
  56. cout << search(1,l,r) << endl;
  57. } else if(tot == 2){
  58. int dis,k;
  59. cin >> dis >> k;
  60. add(1,dis,k);
  61. } else if(tot == 3){
  62. return ;
  63. }
  64. }
  65. }
  66. int main(){
  67. cout << "query section" << endl << "change point" << endl;
  68. Read();
  69. build(1,1,n);
  70. cout << "query 1" << endl << "change 2" << endl << "break 3" << endl;
  71. interaction();
  72. return 0;
  73. }

[C++]线段树 区间查询 单点修改的更多相关文章

  1. hdu 1754 线段树(Max+单点修改)

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  2. hdu 1166 线段树(sum+单点修改)

    敌兵布阵 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submi ...

  3. I Hate It:线段树:单点修改+区间查询

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  4. poj3171 Cleaning Shifts【线段树(单点修改区间查询)】【DP】

    Cleaning Shifts Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4422   Accepted: 1482 D ...

  5. HZAU 1207 Candies(线段树区间查询 区间修改)

    [题目链接]http://acm.hzau.edu.cn/problem.php?id=1207 [题意]给你一个字符串,然后两种操作:1,将区间L,R更新为A或者B,2,询问区间L,R最长的连续的B ...

  6. 【线段树(单点修改,区间求和)】HDU1166 - 敌军布阵

    hdu1166 敌兵布阵,单点修改,区间求和. [ATTENTION]MAXN要开成节点数的4倍,开得不够会提示TLE. #include<iostream> #include<cs ...

  7. HDU - 1166 - 敌兵布阵 线段树的单点修改,区间求和

    #include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> ...

  8. 线段树 区间查询区间修改 poj 3468

    #include<cstdio> #include<iostream> #include<algorithm> #include<string.h> u ...

  9. hdu1754线段树的单点更新区间查询

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  10. HDU 1754 I Hate It(线段树区间查询,单点更新)

    描述 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老 ...

随机推荐

  1. Linux 修改文本dos/unix 格式

    使用 vi 命令打开文件,使用 :set ff 查看格式 如果显示dos,可使用 :set ff=unix 修改 pem 证书,使用 cat xx.key xx.crt DigiCertCA.crt ...

  2. 解决:vue-loader was used without the corresponding plugin.

    原因 webpack经常出现版本不兼容问题,vue-loader在15以前的版本打包时候会自动生成VueLoaderPlugin,但是现在需要手动去wepack.config.js文件中去加入,如下图 ...

  3. 安装deb包

    输入命令: sudo dpkg  -i  file.deb

  4. ABC274 题解

    A 题目:给定 \(A,B\) 输出 \({B}\over{A}\) 保留 \(3\) 位小数. 简答题,和A+B problem 一样,除一除,保留一下小数. B 题目:给定一个 \(n\) 行 \ ...

  5. [postgresql]逻辑备份与还原

    前言 Postgres提供pg_dump和pg_dumpall用于数据库逻辑备份. pg_dumpall:将一个PostgreSQL数据库集群全部转储到一个脚本文件中 pg_dump:可以选择一个数据 ...

  6. QA|20221001|SecureCRT自动断开怎么办?

    Q:SecureCRT自动断开怎么办? A:如下设置

  7. 如何实现一个数据库的 UDF?图数据库 NebulaGraph UDF 功能背后的设计与思考

    大家好,我是来自 BOSS直聘的赵俊南,主要负责安全方面的图存储相关工作.作为一个从 v1.x 用到 v3.x 版本的忠实用户,在见证 NebulaGraph 发展的同时,也和它一起成长. BOSS直 ...

  8. Redis 命令工具

    --- Redis 命令工具 --- redis-server Redis 服务器启动命令 redis-cli shutdown 停止服务 redis-benchmark:性能测试工具,用于检测 Re ...

  9. 利用SpringBoot项目做一个Mock挡板;基于事件发布动态自定义URL和响应报文

    导入SpringbootWEb依赖 <!--web项目驱动--> <dependency> <groupId>org.springframework.boot< ...

  10. 2023-09-30:用go语言,给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1, 每一次移动,你可以选择 相邻 两个数字并将它们交换。 请你返回使 nums 中包含 k

    2023-09-30:用go语言,给你一个整数数组 nums 和一个整数 k . nums 仅包含 0 和 1, 每一次移动,你可以选择 相邻 两个数字并将它们交换. 请你返回使 nums 中包含 k ...