线段树专题
李超线段树
解决一类区间等差数列(线段)求最值的问题。
做法为用线段树来维护,为了使复杂度正确,我们采用标记永久化,并且通过分类讨论,将每次标记下传的大小减半,达到\(O(nlogn)\)的复杂度。
[JSOI2008]Blue Mary开公司 代码
[HEOI2013]Segment
[SDOI2016]游戏
线段树分治
解决一类在时间轴上一段时间里操作有贡献,询问某一时刻的贡献和。
考虑离线的做法,在时间轴上建立线段树。每个节点维护对此区间的贡献,然后最终遍历整个线段树,用一定的数据结构来维护贡献。具体实现的时候,将一个操作看作是对一个区间的修改,将操作存在线段树上节点的vector中,回答询问的时候,只要整体做一次dfs。
二分图
[AHOI2013]连通图
线段树合并、分裂
int merge(int p,int q,int l,int r){
if(!p)return q;if(!q)return p;
if(l==r){t[p].val+=t[q].val;return p;}
int mid=(l+r)>>1;t[p].ls=merge(t[p].ls,t[q].ls,l,mid);t[p].rs=merge(t[p].rs,t[q].rs,mid+1,r);
t[p].val=std::max(t[t[p].ls].val,t[t[p].rs].val);
}
void split(int &p,int q,int k){//权值线段树上分裂出前k小的数,p为后k小
int val=t[t[q].ls].val;
if(k>val)split(t[p].rs,t[q].rs,k-val);
else{
swap(t[p].rs,t[q].rs);
if(k<val)split(t[p].ls,t[q].rs,k);
}
t[p].val=t[q].val-k;t[q].val=k;return;
}