本文共 3114 字,大约阅读时间需要 10 分钟。
将[1,n]分解成若干特定的自取件(数量不超过4*n),然后,将每个区间[L,R]都分解为少量特定的子区间,通过对这些少量子区间的修改或者统计,来实现快速对[L,R]的修改或者统计.
如图表示:#define maxn 100007 //元素总个数int SegTree[maxn<<2]; //线段树//int Lazy[maxn<<2]; //延迟更新标记int A[maxn]; //原始数组
用结构体数组表示
#define maxn 100007int A[maxn];struct SegTreeNode{ int val; //节点值 //int lazy; //懒惰标记,又称延迟更新标记}SegTree[maxn<<2]; //定义线段树
// PushUp函数更新结点信息,这里以求和为例void PushUp(int rt){SegTree[rt].val = SegTree[rt<<1].val + SegTree[rt<<1|1].val;}void build(int l,int r,int rt) //构造根为rt,A区间为[1,r]线段树{ if(l==r){ //叶子节点 SegTree[rt].val=A[l]; return; } int m = (l+r)/2; build(l,m,rt*2); //递归构造左子树 build(m+1,r,rt*2+1); //递归构造右子树 PushUp(rt); //回溯,向上更新}
假设原始数组A[L]+=c
//l,r表示当前结点区间,rt表示当前线段树的根节点编号void Update(int L,int C,int l,int r,int rt){ if(l==r){ //叶节点直接修改 SegTree[rt].val += C; return ; } int m=(l+r)>>1; if(L <= m) Update(L,C,l,m,rt<<1); else Update(L,C,m+1,r,rt<<1|1); PushUp(rt); //回溯,向上更新}
//[L,R]表示操作区间,[l,r]表示当前区间,rt表示当前节点编号int Query(int L,int R,int l,int r,int rt){ if(L<=1 && r <= R) return SegTree[rt].val; //在区间内直接返回 if(L > r || R < 1) return 0; int m = ( l + r ) >> 1; int ANS = 0; if(L <= m) ANS+=Query(L,R,l,m,rt<<1); //左子区间与[L,R]有重叠,递归 if(R > m) ANS += Query(L,R,m+1,r,rt<<1|1); //右子区间与[L,R]有重叠,递归 return ANS; // return Query(L,R,l,m,rt<<1)+Query(L,R,m+1,r,rt<<1|1);//与上面递归部分等价}
是指更新某个