说在前面:
- 关于区间的查询 可以在时间复杂度为O(1)的情况下进行,但是如果加上修改,修改的时间复杂度O(n) :比如让求区间和,我们可以存储前缀和,虽然查询可以在O(1)完成,但是修改的话就要花费大量时间了
- 关于区间的修改,可以在O(1)完成,但是区间的操作 就必须在O(n)下完成:比如我们就存储数据的原本模样,虽然可以在O(1)修改,但是我们的区间和的操作就必须在O(n)下完成了
- 有没有一种方法让两种问题就能得到改善
线段树
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200528105057759.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0MDIzMDEx,size_16,color_FFFFFF,t_70)
- 我们不存储前缀和,我们存储区间和,就像图中画的那样
- 但是树结构存储的空间开销也比较大,所以我们用数组存树
- 已知根节点的 node_head =n(从0开始)
- node_left= node_head*2+1;
- node_right=node_head* 2+2;
- node_head 存的是 从start 到end 的区间和
- ndoe_left 存的是 从start 到 mid 的区间和
- node _right存的是从mid+1 到 end的区间和
- mid =(start+ end)/2
![在这里插入图片描述](https://img-blog.csdnimg.cn/20200528105742318.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ0MDIzMDEx,size_16,color_FFFFFF,t_70)
#include<bits/stdc++.h>
using namespace std;
const int max_len= 1e5;
int tree[max_len];
int arr[max_len]={1,3,5,7,9,11};
void build_tree(int node_head,int start,int end){
if(start==end ){
tree[node_head]=arr[start];
return ;
}
int mid=(start+end)>>1;
int node_left= node_head * 2+1;
int node_right= node_head* 2 +2;
build_tree(node_left,start,mid);
build_tree(node_right,mid+1,end);
tree[node_head]=tree[node_left]+tree[node_right];
}
void updata(int node_head,int start,int end,int idx,int val){
if(start==end){
arr[idx]=val;
tree[node_head]=val;
return ;
}
int mid =(start+ end)>>1;
int node_left= node_head*2 +1;
int node_right=node_head *2+2;
if(mid>=idx){
updata(node_left,start,mid,idx,val);
}else{
updata(node_right,mid+1,end,idx,val);
}
tree[node_head]=tree[node_left]+ tree[node_right];
}
int sum(int node,int start ,int end,int l,int r ){
if(r<start||l>end)return 0;
if(start==end)return tree[node];
if(end<=r&& start>=l)return tree[node];
else{
int mid=(start+end)>>1;
int node_left=node*2+1;
int node_right=node*2+2;
int sum_left=sum(node_left,start,mid,l,r);
int sum_right=sum(node_right,mid+1,end,l,r);
return sum_left+sum_right;
}
}
int n=6;
main(){
build_tree(0,0,5);
for(int a=0;a<=14;a++){
printf("tree[%d]=%d\n",a,tree[a]);
}
for(int a=0;a<=14;a++){
printf("tree[%d]=%d\n",a,tree[a]);
}
cout<<sum(0,0,5,2,4);
}
- 值得注意的是查询区间和的时候 用递归如果要此时的区间在我们要求的区间之间的 ,所以就不用再往下递归,直接把此时的节点数据拿到就行了