线段树
线段树介绍
线段树树基于分治思想的二叉树,用来维护区间信息(区间和、区间最大值、区间最小值等等)。可以在的时间内完成区间信息的查询和修改。
- 线段树中每个叶子结点存储元素本身,非叶子结点存储区间内元素的 统计值
节点数组tr[]
l,r
存区间的左右端点,sum
存区间和
int n,w[N];
struct node{
int l,r,sum;
}tr[N*4];//注意需要开四倍空间
递归建树
父节点的编号为p
左孩子编号为2*p
,右孩子编号为2*p+1
#define lc p<<1
#define rc p<<1|1 或者2*p+1
void build(int p,int l,int r){
tr[p]={l,r,w[l]};
if(l==r) return;//是叶子结点了,直接返回
int mid=l+r>>1;
build(lc,l,mid);
build(rc,mid+1,r);
tr[p].sum=tr[lc].sum+tr[rc].sum;
}
单点修改
从根节点进入,递归找到叶子结点[x,x]
,把该结点的值增加k,然后从下往上更新其祖先节点上的统计值。
void update(int p,int x,int k){//将x位置上的数加k
if(tr[p].l==x && tr[p].r==x){
tr[p].sum+=k;
return;
}
int mid=l+r>>1;
if(x<=mid) update(lc,x,k); //只会进入一个分支
else update(rc,x,k);
tr[p].sum=tr[lc].sum+tr[rc].sum;
}