线段树总介绍
如在阅读本文时遇到不懂的部分,请在评论区询问
1. 线段树是一种基于二叉搜索树的高级数据结构。它可以维护区间,包括求和、最值、某数个数、逆序对、区间合并.......
2. 线段树不仅仅是一种工具,更是一种思想方法。 -- Ryougi Kukoc
3. 下面介绍线段树的基♂操(我写线段树大括号是否换行,用结构体还是数组都很随意...)
//变量 int a[]; //原序列 int sum[],Max[],Min[],pre[],suf[],Maxistr[]; //维护区间: 和、最值、前驱、后继、最大子段和等等
int tag[]; //pt[],mt[],at[];加法、乘法、区间替换tag
#define LS (rt<<1)
#define RS (LS|1)
以下代码仅讲解区间加减、区间求和操作,其它特殊的维护参见 线段树目录 内的对应题解
建树
void build(int rt,int l,int r){ //节点编号,左端点,右端点 if(l==r){ sum[rt]=a[l];return; } int mid=l+r>>1; build(LS,l,mid); build(RS,mid+1,r); pushup(rt); return; }
区间修改
void update(int rt,int l,int r,int x,int y,int k){ if(l>=x&&r<=y){ sum[rt]+=(r-l+1)*k; tag[rt]+=k; return; } if(tag[rt])pushdown(rt,l,r); int mid=l+r>>1; if(x<=mid)update(LS,l,mid,x,y,k); if(y>mid)update(RS,mid+1,r,x,y,k); pushup(rt); }
区间求和
int query(int rt,int l,int r,int x,int y){ if(l>=x&&r<=y) return sum[rt]; if(tag[rt])pushdown(rt,l,r) int mid=l+r>>1,res=0; if(x<=mid)res+=query(LS,l,mid,x,y); if(y>mid)res+=query(RS,mid+1,r,x,y); return res; }
pushdown和pushup
void pushdown(int rt,int l,int r){ //if(!tag[rt])return; tag[LS]+=tag[rt]; tag[RS]+=tag[rt]; int mid=l+r>>1; sum[LS]+=tag[rt]*(mid-l+1); sum[RS]+=tag[rt]*(r-mid); tag[rt]=0; return ; } void pushup(int rt){ sum[rt]=sum[LS]+sum[RS]; }
操作介绍完毕。
End