熟练剖分详解见:https://blog.csdn.net/tangzhide123yy/article/details/77532880
熟练剖分一般有如下几个步骤:
1.dfs1()求出fa,deep,size,son
2.dfs2()求出top,p
3.add()/Query ()树链剖分核心部分
4.updata()线段树更新操作(如单点修改,区间修改)
5.query()线段树查询(如区间查询,单点查询)
建立线段树(维护点权)
inline void build(int l,int r,int rt){
//建立一棵线段树
tr[rt].l=l,tr[rt].r=r;
if(l==r){tr[rt].sum=w[id[l]];return ;}
//w[]存储的为原始的点权,写为w[id[l]]是因为dfs时的顺序不一样
int midd=l+(r-l)/2;
build(l,midd,ls),build(midd+1,r,rs);
pushup(rt);
}
dfs1()维护点权模板
inline void dfs1(int x,int fat,int dep) {
//这里应该就是树链剖分的第一个操作,把树上每个节点的size,fa等统统搞出来
deep[x]=dep,fa[x]=fat,sz[x]=1;//fat表示x的爸爸
for(int i=0;i<g[x].size();i++){
int v=g[x][i];
if(v!=fat){
dfs1(v,x,dep+1);
sz[x]+=sz[v];
//son[x]记录x的儿子中的重点
}
}
}
dfs2()维护点权模板
inline void dfs2(int x,int tp){
//这个操作应该就是处理轻链和重链
top[x]=tp;pos[x]=++cnt;id[pos[x]]=x;