芝士:树剖
作者:互联网
背景
对于一棵树上我们需要查找两个点之间的距离时,很多人的第一反应就是LCA
但是如果加上修改操作呢?就只能用树剖了
操作
基本变量
重量:子树的大小
重儿子:就是最重的那个儿子,
轻儿子:不是重儿子
重链:重儿子组成的链
思想
基于路径的分治,
用线段树来维护重链,
复杂度证明
我们设当前的点为u,当前点的父节点为v
如果v向u的连的边为轻边,
这说明了u不是v的重儿子
也就说明了\(size_v>2*size_u\)
然而总共的点的个数一共就n,
所以一条链上的轻边一定最多有\(log_n\)个
所以向上的复杂度为\(O(log_n)\)
如果v向u连的边为重边
说明u是重儿子,
所以v向u连的边一定是重边
而我们上面又说是用线段树来维护重链时间复杂度为\(O(log_n)\)
而重链一定与轻边相连,轻边最多有\(log_n\)条,所以重链最多有\(log_n\)条
总的时间复杂度即为\(O(log_nlog_n)\)
板子
struct tree_chain_split
{
#define MAXN 100005
struct node
{
int l;
int r;
int lazy;
int val;
}tre[4*MAXN];
void build(int l,int r,int k)
{
tre[k].l=l;
tre[k].r=r;
tre[k].lazy=0;
tre[k].val=0;
if(l==r)
return;
int mid=(l+r)>>1;
build(l,mid,k<<1);
build(mid+1,r,k<<1|1);
}
void pushdown(int k)
{
if(tre[k].lazy==0)
return;
tre[k<<1].lazy+=tre[k].lazy;
tre[k<<1|1].lazy+=tre[k].lazy;
tre[k<<1].val+=tre[k].lazy*(tre[k<<1].r-tre[k<<1].l+1);
tre[k<<1|1].val+=tre[k].lazy*(tre[k<<1|1].r-tre[k<<1|1].l+1);
tre[k].lazy=0;
}
void change_poi(int pos,int k,int add)
{
if(pos>tre[k].r||pos<tre[k].l)
return;
if(tre[k].l==tre[k].r)
{
tre[k].val=tre[k].val+add;
return;
}
pushdown(k);
change_poi(pos,k<<1,add);
change_poi(pos,k<<1|1,add);
tre[k].val=tre[k<<1].val+tre[k<<1|1].val;
}
void change_int(int l,int r,int k,int add)
{
if(l>tre[k].r||tre[k].l>r)
return;
if(l<=tre[k].l&&tre[k].r<=r)
{
tre[k].val=tre[k].val+add*(tre[k].r-tre[k].l+1);
tre[k].lazy=tre[k].lazy+add;
return;
}
pushdown(k);
change_int(l,r,k<<1,add);
change_int(l,r,k<<1|1,add);
tre[k].val=tre[k<<1].val+tre[k<<1|1].val;
}
int query(int l,int r,int k)
{
if(l>tre[k].r||tre[k].l>r)
return 0;
if(l<=tre[k].l&&tre[k].r<=r)
return tre[k].val;
pushdown(k);
return query(l,r,k<<1)+query(l,r,k<<1|1);
}
int cnt;
int w[MAXN];
int fa[MAXN];
int id[MAXN];
int siz[MAXN];
int top[MAXN];
int dep[MAXN];
int wson[MAXN];
vector<int> g[MAXN];
#undef MAXN
void addedge(int u,int v)
{
g[u].push_back(v);
}
void dfs1(int u)
{
siz[u]=1;
dep[u]=dep[fa[u]]+1;
int maxx=-1;
int _ind=0;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa[u])
{
fa[v]=u;
dfs1(v);
siz[u]+=siz[v];
if(siz[v]>maxx)
{
maxx=siz[v];
_ind=v;
}
}
}
wson[u]=_ind;
}
void dfs2(int u,int top_chain)
{
top[u]=top_chain;
id[u]=++cnt;
change_poi(cnt,1,w[u]);
if(!wson[u])
return;
dfs2(wson[u],top_chain);
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa[u]&&v!=wson[u])
dfs2(v,v);
}
}
void init(int len)
{
cnt=0;
build(1,len,1);
dfs1(rt);
dfs2(rt,rt);
}
void change_int(int x,int y,int add)
{
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
swap(x,y);
change_int(id[top[y]],id[y],1,add);
y=fa[top[y]];
}
if(dep[x]>dep[y])
swap(x,y);
change_int(id[x],id[y],1,add);
}
int query(int x,int y)
{
int ret=0;
while(top[x]!=top[y])
{
if(dep[top[x]]>dep[top[y]])
swap(x,y);
ret=ret+query(id[top[y]],id[y],1);
y=fa[top[y]];
}
if(dep[x]>dep[y])
swap(x,y);
ret=ret+query(id[x],id[y],1);
return ret;
}
void change_rot(int x,int add)
{
change_int(id[x],id[x]+siz[x]-1,1,add);
}
int query_rot(int x)
{
return query(id[x],id[x]+siz[x]-1,1);
}
}tre;
标签:return,树剖,int,top,tre,dep,id,芝士 来源: https://www.cnblogs.com/loney-s/p/12158092.html