之前就已经学过了,放在了本地,现在搬到博客园来~
关于线段树的视频学习,强烈推荐B站此大佬的讲解:https://www.bilibili.com/video/BV1cb411t7AM
1.概念:线段树是一种二叉搜索树,与区间树相似。线段树是建立在线段或区间基础上的树,树的每个结点代表一条线段[L,R]。
2:根据视频里的内容,我做出了这张图。arr[]数组,求它区间和,以及对它进行某些数的修改
根据此,有build_tree:
void build_tree(int node,int start,int end) { if(start==end) { tree[node]=arr[start]; } else { int mid=(start+end)/2; int left_node=node*2+1; int right_node=node*2+2; build_tree(left_node,start,mid); build_tree(right_node,mid+1,end); tree[node]=tree[left_node]+tree[right_node]; } }
对于update,需要修改arr[]的某个数,改变最下面的start==end的结点,那么上面跟它有关系的结点都要进行更新。start==end依然是作为递归的出口。看idx的位置,在左孩子里就更新左孩子,否则右孩子。
void update_tree(int node,int start,int end,int idx,int val) { if(start==end) { tree[node]=val; arr[idx]=val; } else { int mid=(start+end)/2; int left_node=node*2+1; int right_node=node*2+2; if(idx>=start&&idx<=mid) update_tree(left_node,start,mid,idx,val); else update_tree(right_node,mid+1,end,idx,val); tree[node]=tree[left_node]+tree[right_node]; } }
然后是求区间和操作。基本一致。只是这里要注意一下递归结束条件的优化:
int query_tree(int arr[],int tree[],int node ,int start,int end,int l,int r) { if(r<start||l>end) { return 0; } else if(l<=start&&end<=r) { return tree[node]; } else if(start==end) { return tree[node]; } else { int mid=(start+end)/2; int left_node=node*2+1; int right_node=node*2+2; int sum_left=query_tree(arr,tree,left_node,start,mid,l,r); int sum_right=query_tree(arr,tree,right_node,mid+1,end,l,r); return sum_left+sum_right; } }
总的代码:
#include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int maxn=1000; void build_tree(int arr[],int tree[],int node,int start,int end) { if(start==end){ tree[node]=arr[start]; } else { int mid=(start+end)/2; int left_node=2*node+1; int right_node=2*node+2; build_tree(arr,tree,left_node,start,mid); build_tree(arr,tree,right_node,mid+1,end); tree[node]=tree[left_node]+tree[right_node]; } } void update_tree(int arr[],int tree[],int node,int start,int end,int idx,int val) { if(start==end) { arr[idx]=val; tree[node]=val; } else { int mid=(start+end)/2; int left_node=node*2+1; int right_node=2*node+2; if(idx>=start&&idx<=mid) { update_tree(arr,tree,left_node,start,mid,idx,val); } else { update_tree(arr,tree,right_node,mid+1,end,idx,val); } tree[node]=tree[left_node]+tree[right_node]; } } int query_tree(int arr[],int tree[],int node ,int start,int end,int l,int r) { if(r<start||l>end) { return 0; } else if(l<=start&&end<=r) { return tree[node]; } else if(start==end) { return tree[node]; } else { int mid=(start+end)/2; int left_node=node*2+1; int right_node=node*2+2; int sum_left=query_tree(arr,tree,left_node,start,mid,l,r); int sum_right=query_tree(arr,tree,right_node,mid+1,end,l,r); return sum_left+sum_right; } } int main() { int arr[]={1,3,5,7,9,11}; int size=6; int tree[maxn]={0}; build_tree(arr,tree,0,0,size-1); for(int i=0;i<15;i++) cout<<tree[i]<<" "; cout<<endl; update_tree(arr,tree,0,0,size-1,4,6); for(int i=0;i<15;i++) cout<<tree[i]<<" "; cout<<endl; cout<<query_tree(arr,tree,0,0,size-1,2,4); }