长链剖分 入门

长链剖分

额,其实和树剖差不多,对于每个节点 u 维护 mxdu 为子树内节点深度最大值。

那么令 Son(u) 里取到 mxdv 最大的儿子 v 为长儿子,类似重链剖分处理即可。

同样令连接不同长链的两个点之间的边为虚边。

有如下性质:

  • 从根到节点 u,所经过虚边个数不超过 O(n),这是因为从 u 开始往上走,所走到的每一条长链其长度都是严格长于当前长链的,即使 mxd 相同,往上走的那条链至少还会加上父亲,这告诉我们走到根,所有的长链最多也就是 1+2+3n
  • 每条链底是叶子,且是子树内最深节点
  • 节点 uk 级祖先所在长链长度不小于 k

O(nlogn)O(1) 树上 k 级祖先

我们先利用倍增预处理出 fu,iu2i 级祖先,lgi=log2(i)

查询 uk 级祖先,先查 x=fu,lgkk=k2lgk

这样就满足 x 所在长链长度 >k

我们对于每个链,维护从链顶往上走 0len 和往下走 0len 的节点,就可以分类讨论 depxdeptopxk 的大小关系找到 k 级祖先了

在存储时,我们可以类似树剖进行 dfn 重标号,将 u 存下 topu 往上走 depudeptopu 步的节点。

void dfs(int u,int fa){
    f[u][0]=fa;dep[u]=dep[fa]+1;mxd[u]=dep[u];
    for(int i=1;i<=19;++i)f[u][i]=f[f[u][i-1]][i-1];
    for(auto v:e[u])if(v!=fa){
        dfs(v,u);if(mxd[v]>mxd[u])son[u]=v,mxd[u]=mxd[v];
    }
}
void dfs2(int u,int tp,int lt){
    dfn[u]=++idx;down[idx]=u;up[idx]=lt;top[u]=tp;
    if(!son[u])return ;
    dfs2(son[u],tp,f[lt][0]);
    for(auto v:e[u])if(v!=f[u][0]&&v!=son[u])dfs2(v,v,u);
}
int get(int x,int k){
    if(!k)return x;
    x=f[x][lg[k]];
    k-=1ll<<lg[k];
    int d=dep[x]-dep[top[x]];
    if(d>=k)return down[dfn[x]-k];
    return up[dfn[top[x]]+k-d-1];
}

优化 dp

长链剖分可以优化 维护仅与深度有关的一个信息 的 dp。

例如子树内深度为 k 的节点个数/子树内深度出现次数众数等。

一般形式是设 dpu,k 为子树内深度取 k 的答案。

在 dp 时采用 dfs 形式,设当前是 dfs(u,tp),我们遵循以下步骤:

  • u=tp,开一个 vector 长度为 mxdudepu+1 存储每个深度 deptp 的 dp 值。
  • 优先递归长儿子
  • 递归非长儿子,并暴力合并信息(枚举长儿子第二维 j 并找到在 dptp 的相应位置进行更新)
  • 加入点 u 的信息
  • 统计答案

注意到存储的时候有个 deptp 的下标偏移。

模板:求各个点子树内各个节点深度的众数。

void dfs2(int u,int tp){
    if(u==tp)f[u].resize(mxd[u]-dep[u]+1);
    if(son[u])dfs2(son[u],tp);
    for(auto v:e[u])if(v!=lt[u]&&v!=son[u]){
        dfs2(v,v);
        for(int i=0;i<f[v].size();++i){
            f[tp][i-dep[tp]+dep[v]]+=f[v][i];
            if(f[tp][i-dep[tp]+dep[v]]>mx[tp]||(f[tp][i-dep[tp]+dep[v]]==mx[tp]&&i-dep[tp]+dep[v]<id[tp]))mx[tp]=f[tp][i-dep[tp]+dep[v]],id[tp]=i-dep[tp]+dep[v];
        }
    }
    f[tp][dep[u]-dep[tp]]++;
    if(f[tp][dep[u]-dep[tp]]>mx[tp]||f[tp][dep[u]-dep[tp]]==mx[tp]&&dep[u]-dep[tp]<id[tp])mx[tp]=f[tp][dep[u]-dep[tp]],id[tp]=dep[u]-dep[tp];
    ans[u]=id[tp]-dep[u]+dep[tp];
    // cout<<"dfs2 "<<u<<' '<<mx[tp]<<" "<<id[tp]<<"\n";
}
posted @   spdarkle  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示