hotmanの備忘録とライブラリ置き場.

【競技プログラミング】重心分解を25行で書く方法

はじめに

重心分解は 25 行程度でかけます
(わかりやすい様にコメント付加してたら 30 行程度になってしまいました)
ポイントは重心分解によって出来る木を BFS でなく DFS で潜ることです!!!

Centroid_Decomposition.cpp
vector<vector<int>>g;//元の木の隣接リスト
vector<int>used;//重心が確定したか
vector<int>v;//重心分解後の木のDFS順の列
vector<vector<int>>ch;//重心分解後の木の親子関係
int s;//重心分解後の木の根
int dfs(int n,int p,int sz,int root){
    constexpr int inf=g.size()*2;
    if(used[n])return 0;
    bool b=1;
    int res=1;
    for(auto e:g[n]){
        if(p==e)continue;
        auto t=dfs(e,n,sz,root);
        res+=t;
        if(t>sz/2)b=0;
    }
    if(!b||sz-res>sz/2)return res;//重心で無いなら部分木のサイズを返す

    //重心を登録
    if(root!=-1)ch[root].push_back(n);
    else s=n;
    v.push_back(n);
    used[n]=1;

    //重心分解後の木で自身の子となる重心を探す
    //dfs(e,n,inf,n)では部分木のサイズを求めてる
    //(szをinfにすると当然重心が見つからないため部分木のサイズが返る)
    for(auto e:g[n])dfs(e,n,dfs(e,n,inf,n),n);

    //重心はすでに見つかったためinf=g.size()*2を返す
    return inf;
}

v には重心分解後の木を dfs した結果が入ります(なくてもいいかも)
ch には、重心分解後の木における子供が入ります
s は重心分解後の木の根が入ります
dfs の挙動は見たままです。は?(質問がある方はtwitterまで)

verify

Ciel the Commander -codeforces
解答例

The source code for this blog is available on GitHub.