重链剖分

,,引言:
      

        所谓重链剖分,通俗地说,就是将树剖分成一条一条的链,就像从树上折下树枝,同时对最重的树枝细心呵护(最重的树枝,不同俗地讲,就是儿子最多的)

        好,我们切入正题


 基本概念: 

        重儿子:表示其子节点中子树最大(就是所含的点最多咯,懂得都懂)的子结点。如果有多个子树最大的子结点,取其一。如果没有子节点,就无重儿子。

        轻儿子:不是重儿子的儿子 十分合理吧

        重边:从这个结点到重子节点的边为 重边

        轻边:到其他轻子节点的边为 轻边

        重链:若干条首尾衔接的重边构成 重链(把落单的结点也当作重链)

        画个极端的图吧,嘿嘿,便于理解

 

实现:
        

        两遍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序为连续的,可以使用线段树、树状数组维护树上的信息

在线段树、树状数组上维护信息,相信大家都会,不多讲。主要是将链拆成连续的区间

假设树上有两个点 x,y ,求 xy 的路径上的点的区间(注: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]为所求的最后一段区间
}

累了累了,我写不下去了,拜拜

posted @   MegaSam  阅读(10)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示