重链剖分
,,引言:
所谓重链剖分,通俗地说,就是将树剖分成一条一条的链,就像从树上折下树枝,同时对最重的树枝细心呵护(最重的树枝,不同俗地讲,就是儿子最多的)
好,我们切入正题
基本概念:
重儿子:表示其子节点中子树最大(就是所含的点最多咯,懂得都懂)的子结点。如果有多个子树最大的子结点,取其一。如果没有子节点,就无重儿子。
轻儿子:不是重儿子的儿子 十分合理吧
重边:从这个结点到重子节点的边为 重边
轻边:到其他轻子节点的边为 轻边。
重链:若干条首尾衔接的重边构成 重链(把落单的结点也当作重链)
画个极端的图吧,嘿嘿,便于理解
实现:
两遍dfs,求出所需的信息即可
//size: 子树的大小 depth: 点的深度 fa: 点的父亲 son: 点的重儿子
void dfs1(int u,int father){
size[u]=1;
depth[x]=depth[father]+1;
fa[x]=father;
int maxson=-1;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v==father) continue;
dfs1(v,u);
size[u]+=size[v];
if(size[v]>maxson)
maxson=size[v],son[x]=v
}
}
//id: dfs序 top: 重链的链顶
void dfs2(int u,int topf){
id[u]=++tot;
top[u]=topf;
if(!son[u]) return ;
dfs2(son[u],topf);
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(v==fa[u]||v==son[u]) continue;
dfs2(y,y);
}
}
应用:
由于链上的dfs序为连续的,可以使用线段树、树状数组维护树上的信息
在线段树、树状数组上维护信息,相信大家都会,不多讲。主要是将链拆成连续的区间
假设树上有两个点 ,求
到
的路径上的点的区间(注:dfs序的区间)
易知,若x,y 在一条链上,就只有一段连续区间
而后若不在一条链上,那么就是有多端连续区间组成的
void work(int x,int y){
while(top[x]!=top[y]){ //不在同一条链上
if(depth[x]<depth[y])
swap(x,y);
//id[top[x]]~id[x]为一段所求区间
x=fa[top[x]];
}
if(x==y) return;
if(depth[x]>depth[y]) swap(x,y);
//id[x]~id[y]为所求的最后一段区间
}
累了累了,我写不下去了,拜拜
本文来自博客园,作者:MegaSam,转载请注明原文链接:https://www.cnblogs.com/MegaSamTXL/p/17607131.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】