树链剖分
不是联赛内容,但是用得多,就先整着
树链剖分
树剖,其实就是将一棵树剖成若干条链,来解决树上的路径问题.
剖成链有什么用呢?主要是把它组合成一个线性结构,然后拿数据结构去维护.
下面主要讲的是重链剖分,因为长链剖分一般很少涉及到,以后有涉及再写.
维护几个信息:
-
重儿子
son[x]:点 x 的子节点中子树最大的子节点,从 x 到 son[x] 的边称为重边; -
子树大小
siz[x]:以点 x 为根的子树大小(节点数); -
dfs 序
dfn[x]:这个没什么好说的; -
链顶点
top[x]:点 x 所在重链的顶部节点.
一共需要进行两遍 dfs 操作,第一遍进行找重边,第二遍进行连接重边.
实现:
inline void dfs1(ll x,ll fa)
{
f[x]=fa;dep[x]=dep[fa]+1;siz[x]=1;son[x]=0;
for(rll i=0;i<g[x].size();i++)
{
rll to=e[i].to;if(to==fa) continue; dfs1(to,x);siz[x]+=siz[to];
if(siz[to]>siz[son[x]]) son[x]=to;
}
}
inline void dfs2(ll x,ll fa)
{
dfn[x]=++cnt;top[x]=fa; if(son[x]) dfs2(son[x],fa);
for(rll i=0;i<g[x].size();i++) { rll to=e[i].to; if(dfn[to]) continue; dfs2(to,to); }
}
剖分完之后就可以用数据结构去维护每一个链,就相当于维护每一个区间.
修改操作:
当要修改的区间在同一条重链上时,直接用数据结构进行区间修改;如果不在,就需要把它们不断往一条链上靠.
怎么进行?
设两个点分别为 x 和 y. 如果点 x 所在重链顶端的点的父亲与 y 处在同一条重链上,那就把点 x 与 top[x] 间的权值进行修改,跳上去再修改就行了.
如果出现需要经过多条重链的,就不断进行上述操作.
如果都要向上跳呢?
每次找到 dep[top[i]] 更大的 i 去修改从 i 到 top[i] 间每个点的权值,不断向上跳直至到达同一条重链.
实现:
inline void modify(rll x,rll y,rll v)
{
while(top[x]^top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
upd(dfn[top[x]],dfn[x],v);// 使用数据结构实现区间修改
x=top[x];
}
if(dep[x]>dep[y]) swap(x,y);
upd(dfn[x],dfn[y],v);// 使用数据结构实现区间修改
}
LCA
即最近公共祖先.
两种常用的求 LCA 方法:
-
倍增
这不是树剖嘛我怎么在写倍增
二进制是个好东西,倍增思想充分利用了这个特点.
令 fa[i][j] 表示点 i 的 2j 层祖先.
方法就是:fa[i][j]=fa[fa[i][j-1]][j-1].
fa[i][0] 就是 i 的父亲节点了.
找 LCA:
也是利用二进制拆分,把深度大的点不断进行节点上翻 if(fa[i][j]) i=fa[i][j];.
然后在同一层时把两个点同时向上翻,直至 fa[x][0]=fa[y][0]. 那么 fa[x][0] 就是 LCA.
实现:
inline ll getd(rll x,rll y)
{
for(rll i=0;i<=16;i++) if((1<<i)&y) x=fa[x][i];
return x;
}
inline ll lca(rll x,rll y)
{
if(x==1||y==1) return 1; if(dep[x]<dep[y]) swap(x,y);
x=getd(x,dep[x]-dep[y]); if(x==y) return x;
for(rll i=16;~i;i--) if(fa[x][i]^fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
-
树剖
和上面树剖查询的类似. 也是不断往一条重链上靠.
实现:
inline ll lca(rll x,rll y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]]) swap(x,y);
x=f[top[x]];
}
if(dep[x]<dep[y]) return x; return y;
}
--END--

浙公网安备 33010602011771号
我的博客: 𝟷𝙻𝚒𝚞
本文链接: https://www.cnblogs.com/1Liu/articles/16777976.html
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!