线段树(sgement tree)是一种分治思想的二叉树结构,用于在区间上进行信息统计。与按照二进制位进行区间划分的树状数组相比,线段树是一种更加通用的结构:
- 线段树的每个节点都代表一个区间。
- 线段树具有唯一的根节点,代表的区间是整个统计范围,如[1,n]。
- 线段树的每个叶节点都代表一个长度为1的元区间,如[x,x]
线段树是一种二叉搜索树,与区间树相似,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点。
使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。
在这片文章中,我先讲一下最基本的建树,单点修改,单点/区间查询
线段树是一种用空间换时间的算法开建树的数组时切记 一定要开4倍的数组
#include<bits/stdc++.h> using namespace std; const int maxn=10000+10; int a[maxn],sum[maxn*4]; //四倍空间 inline int read(){ //快读,没啥特殊意思 int s=0,w=1; char ch=getchar(); while(ch<='0' || ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0' && ch<='9'){s=s*10+ch-48;ch=getchar();} return s*w; } inline void pushup(int root){ //这个节点的值是该节点的左节点加右节点的和 sum[root] = sum[root<<1]+sum[root<<1|1]; }//乘2是该节点的左节点,再加1则是右节点 inline void build(int l,int r,int root){//建树 if(l == r){ sum[root] = a[l]; return; } int mid = (l+r)>>1; build(l,mid,root<<1); build(mid+1,r,root<<1|1); pushup(root); } inline void update(int l,int r,int root,int num,int w){//更新 if(l == r){ sum[root] += w; return; } int mid = (l+r)>>1; if(num <= mid)update(l,mid,root<<1,num,w); if(num > mid)update(mid+1,r,root<<1|1,num,w); pushup(root); } inline int query(int l,int r,int root,int num){//查询 if(l == r)return sum[root]; int mid = (l+r)>>1; if(num <= mid)return query(l,mid,root<<1,num); if(num > mid)return query(mid+1,r,root<<1|1,num); } inline int query2(int root,int l,int r,int L,int R){//区间查询 if(L <= l && r <= R) return sum[root]; int mid = (l+r)>>1,tmp = 0; if(L <= mid) tmp += query2(root<<1,l,mid,L,R); if(mid < R) tmp += query2(root<<1|1,mid+1,r,L,R); return tmp; } int main(){ int n; n = read(); for(int i = 1;i <= n;i++)scanf("%d",&a[i]); build(1,n,1); // for(int i = 1;i <= n*2-1;i++)printf("%d%c",sum[i],i == n?' ':' '); for(int i = 1,op,x,y,L,R;i <= 10;i++){ scanf("%d",&op); if(op == 1)scanf("%d%d",&x,&y),update(1,n,1,x,y); if(op == 2)scanf("%d",&x),printf("%d ",query(1,n,1,x)); if(op == 3)scanf("%d%d",&L,&R),printf("%d ",query2(1,1,n,L,R)); } return 0; }
数组实现线段树建树,单点修改,区间/单点查询
如果单单只是区间查询就没必要pushdowm,用不着
结构体的就懒得打了
自己想去