[C++]线段树 区间查询 单点修改
线段树 区间查询 单点修改
算法思想
这个算法是用于数组的查询和修改
可以高效的进行查询修改
但是会增加内存的使用
本质上是一种 空间换时间 的算法
这个算法把一串数组无限二分
直到分的只剩下一个数据

将每一段看成一个节点
这样就组成了一个树形结构
故名 线段树
代码实现
实现这个代码一共分三个步骤:
建树 查询 修改
这里先把变量含义解释一遍:
#define maxn 1000010
#define mid ((l+r)>>1)
#define li i<<1
#define ri 1+(i<<1)
/*
mid 线段中间节点的小标
li i线段的左子树
ri i线段的右子树
*/
int n,val[maxn];
/*
n 数组的长度
val 数组的值
*/
struct Node{
int l,r,sum;
}tree[maxn];
/*
tree 即这个树形结构
tree[i].l i线段的左端
tree[i].r i线段的右端
tree[i].sum i线段的所有节点的权值和
*/
建树
void build(int i,int l,int r){
tree[i].l = l;
tree[i].r = r;
if(l == r){
tree[i].sum = val[l];
return ;
}
build(li,l,mid);
build(ri,mid+1,r);
tree[i].sum = tree[li].sum + tree[ri].sum;
return ;
}
欲建树 先分步
我们只要处理好每个节点的三个值(l,r,sum)
这棵树自然也就建好了
l,r直接赋值即可
如果 if(l == r)
则说明这个节点已经无法再二分了
那么就把 \(val\) 的值直接赋给 \(sum\)
并且要记得 return ;
若 \(l != r\)
那就继续二分建子树
然后再把两个子树的值加起来即为自己的 \(sum\)
查询
int search(int i,int l,int r){
if(l <= tree[i].l && tree[i].r <= r)
return tree[i].sum;
if(tree[i].r < l || r < tree[i].l)
return 0;
int ans = 0;
if(tree[li].r >= l) ans += search(li,l,r);
if(tree[ri].l <= r) ans += search(ri,l,r);
return ans;
}
这步的主要思想是能大块就返回大块的值
不能再二分给儿子线段处理
由于已经把数组分得很细
因此不存在查询边界在线段中却无法二分的情况

- \(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\)
和上面同理
有区间一部分在右子线段上
修改
void add(int i,int dis,int k){
if(tree[i].l == tree[i].r){
tree[i].sum += k;
return ;
}
if(dis <= tree[li].r)
add(li,dis,k);
else
add(ri,dis,k);
tree[i].sum = tree[li].sum + tree[ri].sum;
return ;
}
修改我自身感觉和建树有点相像
就是改变一个节点的值然后再将涉及到这个节点的线段重新建树
- \(tree[i].l == tree[i].r\)
这代表已经找到了这个节点
那就把这个点的值修改掉
- \(dis <= tree[li].r\)
如果在线段里
那就继续找
- \(tree[i].sum = tree[li].sum + tree[ri].sum;\)
更新线段的值
线段数 区间修改 单点查询
Code
#include<bits/stdc++.h>
#define maxn 1000010
#define mid ((l+r)>>1)
#define li i<<1
#define ri 1+(i<<1)
using namespace std;
int n,val[maxn];
struct Node{
int l,r,sum;
}tree[maxn];
void Read(){
cin >> n;
for(int i = 1;i <= n;i++)cin >> val[i];
}
void build(int i,int l,int r){
tree[i].l = l;
tree[i].r = r;
if(l == r){
tree[i].sum = val[l];
return ;
}
build(li,l,mid);
build(ri,mid+1,r);
tree[i].sum = tree[li].sum + tree[ri].sum;
return ;
}
int search(int i,int l,int r){
if(l <= tree[i].l && tree[i].r <= r)
return tree[i].sum;
if(tree[i].r < l || r < tree[i].l)
return 0;
int ans = 0;
if(tree[li].r >= l) ans += search(li,l,r);
if(tree[ri].l <= r) ans += search(ri,l,r);
return ans;
}
void add(int i,int dis,int k){
if(tree[i].l == tree[i].r){
tree[i].sum += k;
return ;
}
if(dis <= tree[li].r)
add(li,dis,k);
else
add(ri,dis,k);
tree[i].sum = tree[li].sum + tree[ri].sum;
return ;
}
void interaction(){
while(1){
int tot;
cin >> tot;
if(tot == 1){
int l,r;
cin >> l >> r;
cout << search(1,l,r) << endl;
} else if(tot == 2){
int dis,k;
cin >> dis >> k;
add(1,dis,k);
} else if(tot == 3){
return ;
}
}
}
int main(){
cout << "query section" << endl << "change point" << endl;
Read();
build(1,1,n);
cout << "query 1" << endl << "change 2" << endl << "break 3" << endl;
interaction();
return 0;
}
[C++]线段树 区间查询 单点修改的更多相关文章
- hdu 1754 线段树(Max+单点修改)
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- hdu 1166 线段树(sum+单点修改)
敌兵布阵 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submi ...
- I Hate It:线段树:单点修改+区间查询
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- poj3171 Cleaning Shifts【线段树(单点修改区间查询)】【DP】
Cleaning Shifts Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4422 Accepted: 1482 D ...
- HZAU 1207 Candies(线段树区间查询 区间修改)
[题目链接]http://acm.hzau.edu.cn/problem.php?id=1207 [题意]给你一个字符串,然后两种操作:1,将区间L,R更新为A或者B,2,询问区间L,R最长的连续的B ...
- 【线段树(单点修改,区间求和)】HDU1166 - 敌军布阵
hdu1166 敌兵布阵,单点修改,区间求和. [ATTENTION]MAXN要开成节点数的4倍,开得不够会提示TLE. #include<iostream> #include<cs ...
- HDU - 1166 - 敌兵布阵 线段树的单点修改,区间求和
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> ...
- 线段树 区间查询区间修改 poj 3468
#include<cstdio> #include<iostream> #include<algorithm> #include<string.h> u ...
- hdu1754线段树的单点更新区间查询
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total ...
- HDU 1754 I Hate It(线段树区间查询,单点更新)
描述 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感.不管你喜不喜欢,现在需要你做的是,就是按照老师的要求,写一个程序,模拟老师的询问.当然,老 ...
随机推荐
- Hexo博客yilia主题添加背景音乐 (网易云音乐)
1. 打开网易云音乐首页,然后搜索你要添加的背景音乐 http://music.163.com/ 2. 搜索到歌曲点击生成外链播放器,进去下一个界面 3. 复制外链播放器的代码 打开yilia主题下的 ...
- CS144 LAB0~LAB4
CS144: LAB0 0.写在前面 这更倾向于个人完成 lab 后的思考和总结,而不是 CS144 lab 答案或者 lab document 翻译(指南或者翻译已经有大佬做的很好了,下面已经贴出链 ...
- 2023郑州轻工业大学校赛邀请赛wh
在这里,很感谢程立老师的帮助和选择我,我以后会跟着程老师,既然热爱,就要走下去! 2022年4月2号,我代表河南工业大学与郑州17所高校在郑州轻工业大学举办的"卓见杯"郑州轻工业大 ...
- 2023-07-19:布尔表达式 是计算结果不是 true 就是 false 的表达式 有效的表达式需遵循以下约定: ‘t‘,运算结果为 true ‘f‘,运算结果为 false ‘!(subExpr
2023-07-19:布尔表达式 是计算结果不是 true 就是 false 的表达式 有效的表达式需遵循以下约定: 't',运算结果为 true 'f',运算结果为 false '!(subExpr ...
- 聊聊又拍云存储 S3 协议的使用
近期,有细心的同学发现,在又拍云控制台中的云存储产品中增加了针对 S3 协议标准的兼容支持,授权用户通过 S3 协议标准对存储空间的数据进行读写操作.此配置操作之前是由人工协助的方式提供给用户使用的, ...
- 树莓派命令——linux命令tips
sudo python3 test.py 和 python3 test.py 完全不是一个东西,有时候是链接的编译器不同,环境是完全不同,sudo会调用一些无关资源,反而容易造成程序运行失败或浪费cp ...
- 【心得】C51单片机_中断
@ 目录 ①学习单片机中断总思想 ②学习单片机中断总思想 ③学习单片机中断总方法 外部中断 定时计数器中断 串行口中断 ④总结 附 ①学习单片机中断总思想 标题客观的说,学习单片机只需要掌握 I/O ...
- 关于自定义程序打包成jar包,并读取配置
前言 在实际开发过程中,我们有时候有把你编写的一段程序打成jar包的需求,而一些配置是需要去配置文件里面读取关于这项目的一些配置,本人在网络上查询了众多的资料,总的来说可以归为3类 1.从数据库读取配 ...
- Redhat 8.2 系统语言切换(英文转中文)
前提条件 确保已连上网,并且配好 yum 源 若未配好 yum 源 可参考我上一篇文章 部分 Linux 换国内源 操作步骤 安装中文语言包 dnf install glibc-langpack-zh ...
- 三维模型OBJ格式轻量化压缩变形现象分析
三维模型OBJ格式轻量化压缩变形现象分析 三维模型的OBJ格式轻量化压缩是一种常见的处理方法,它可以减小模型文件的体积,提高加载和渲染效率.然而,在进行轻量化压缩过程中,有时会出现模型变形的现象,即压 ...