グラフ理論と09の出会い:木のヒューリスティックマージ

ヒューリスティックツリー合併

この例を見て:

長所与\(^ 5 10 \)配列、配列は、(\ [0,1000000])\整数であり、そこである(10 ^ 5 \)を\ビュー質問は、質問は二種類あった:レビュー配列の位置の値、およびクエリー間隔\([L、R] \ ) 内にどのように多くの異なる数の合計。

セグメントツリーのアプローチとはみなされません。私たちはチームで問題を解決すると考えることができます---モリブデンMoはバレルとチームのルーチンに従ってソートされた100万バレルの複雑さまで維持することができます\(O(N \のSQRT {N})\) あなたが見ることができ、私たちの核となるアイデアは、それによって複雑さを軽減、それぞれの場所でアクセスのソート順を変更することです。

その後、我々は(次の例を参照してください上記は、DSUを惹起しない場合、私は発声のだろうか?):

所与のサイズの\(10 ^ 6 \)ツリーは、各ツリーは、点である\([0,1000000] \)は、整数があるれている\(10 ^ 5 \)回のクエリ、クエリサブツリー内でどのように多くの異なる数の合計。

ツリーのMoチームは?しかし、今、私はする必要があります(NlogN \)\アルゴリズムを。だから我々は、Moのチームの考え方を参照してください、それはアクセス順序を変更することで、複雑さを低減することができますか?このアルゴリズムは、一般的に書かれた、「木のヒューリスティックマージ」と呼ばれている(DSU \)\

暴力に対処する、暴力の実践を検討するすべてのサブツリー、そしてに対する答えです\(O(1)\)の答え。再帰的に各点のために、その後、ツリー全体をトラバース\(U \) 算出した暴力\(U \)解答サブツリー。複雑\(O(N ^ 2)\)

私たちは、の計算に仕上がっ\(U \)の息子\(V \)答えた後、我々は計算する必要が\を(V \)への答え\(U \)の貢献、そして\(V \)の答えは削除します。だから我々は、最後のサブツリーへの答えは削除する必要はありません発見しました。我々は確かに大きなサブツリーが、最終的な処理を置くだろうと考え、私たちの比較。重鎖分割:その後、我々は別の美しいものを見つけました。そのため、重鎖分割の練習で、私たちは木のサイズを小さく、光の後に彼の息子に行くたびになり、少なくとも\(\ FRAC。1} {2} {\) そのため、ほとんどのルートへのパス上の各ノード\(\ log_2n \)の各点は、祖先トラバーサルさらにエッジに接続された光を得られる、光側ストリップ(\ \ log_2nの\)倍。だから我々は、最終的なプロセスにツリーをバリオン、優先順位は、彼らのレプトンツリーを終えるコンピューティングのすべての重い側の接続の先祖のルートに続い光側、ウォーキングや暴力的な回答プロセスレプトンツリー、ルート重い息子を行きます答えはこの時点まで存在しないので、ポイントの数を横断する前に等しく(log_2n + 1 \)\複雑さがされ(NlogN \)を\します

要約すると、アルゴリズムの基本的な流れは次のとおりです。\(O(N)\)重鎖スプリット、\(O(nlogn)\)時点の各々は、処理光回答のサブツリーに横断する前記ツリーのヒューリスティックは、組み合わせ情報レプトンツリーで自分の答えを更新し、重い息子を横断、レプトンツリー情報を削除します。最後に\(O(M)\)の答え。


ここでは例を示します。

CF741Dアルパの手紙、マークツリーとMehrdadのDokhtar-koshパス

ツリー1のルートは、それぞれの側は、文字(22種のAV)を有しています。簡単なパスがあればDokhtar-koshと呼ばれ、パス上の文字が後にパリンドローム配列に並べ替えている場合のみです。最長ツリー長Dokhtar-kosh各サブ経路を求めます。

\(1 {\当量}、N {\当量} 5×10 ^ 5 \)


プロパティは明白です:数は最大1つのパスのパリンドローム奇数文字の上に表示されます。その後、我々は聞かせて、圧力を形成することができます(私は\)\その後、せいぜい22例、列挙ができ、文字の数がパス上に奇妙な状態を表示さ表しています。

最長パスの必要な長さ以来、私たちはセット\は(uは\)です\(V \)祖先の、およびuの同じ、そしてVのルートにパリティ状態パス\(V \)明らかに優れ\(U \ )、ので\(V \)より深く。だから我々は、アレイの設定\(cnt_iを\)状態のパスを示します\(私は\)最大の深さを。

パスの状態を取得する方法?エンドポイント設定パスが\(Uを、V \) 次いで状態である\(state_u \) ^ \(state_v \) ^ \(STATE_ {LCA} \) ^ {STATE_ {LCA}}、ここで\(state_x \ )を表す\(X \)ルート状態にパリティパスを。

、アルゴリズムは第一\(O(N)\)重鎖分割、およびプロセス\(状態\)アレイ;および\(DSU \) 時間の複雑さはある\(O(nlogn)\)

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 500010
using namespace std;

int dep[maxn],son[maxn],size[maxn],ldfn[maxn],rdfn[maxn],id[maxn],dfn;
int col[maxn],cnt[(1<<22)-1],state[maxn],ans[maxn];
int n,nowson;

struct edge{
    int to,col,next;
}e[maxn<<1];
int head[maxn],k;

inline void add(const int &u,const int &v,const int &w){
    e[k]=(edge){v,w,head[u]},head[u]=k++;
}

void dfs_getson(int u,int fa){
    size[u]=1,ldfn[u]=++dfn,id[dfn]=u;
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==fa) continue;
        dep[v]=dep[u]+1,state[v]=state[u]^e[i].col,dfs_getson(v,u),size[u]+=size[v];
        if(size[v]>size[son[u]]) son[u]=v;
    }
    rdfn[u]=dfn;
}

void dsu(int u,int fa,bool op){
    for(register int i=head[u];~i;i=e[i].next){
        int v=e[i].to;
        if(v==fa||v==son[u]) continue;
        dsu(v,u,false),ans[u]=max(ans[u],ans[v]);
    }
    if(son[u]) dsu(son[u],u,true),ans[u]=max(ans[u],ans[son[u]]);
    if(cnt[state[u]]) ans[u]=max(ans[u],cnt[state[u]]-dep[u]);
    for(register int i=0;i<22;++i) if(cnt[state[u]^(1<<i)])
        ans[u]=max(ans[u],cnt[state[u]^(1<<i)]-dep[u]);
    cnt[state[u]]=max(cnt[state[u]],dep[u]);
    for(register int i=head[u];~i;i=e[i].next){
        register int v=e[i].to;
        if(v==fa||v==son[u]) continue;
        for(register int j=ldfn[v];j<=rdfn[v];++j){
            register int w=id[j];
            if(cnt[state[w]]) ans[u]=max(ans[u],cnt[state[w]]+dep[w]-2*dep[u]);
            for(register int k=0;k<22;++k) if(cnt[state[w]^(1<<k)])
                ans[u]=max(ans[u],cnt[state[w]^(1<<k)]+dep[w]-2*dep[u]);
        }
        for(register int j=ldfn[v];j<=rdfn[v];++j) cnt[state[id[j]]]=max(cnt[state[id[j]]],dep[id[j]]);
    }
    if(!op) for(register int i=ldfn[u];i<=rdfn[u];++i) cnt[state[id[i]]]=0;
}

int main(){
    memset(head,-1,sizeof head);
    cin>>n;
    for(register int i=2;i<=n;++i){
        int to; char col;
        cin>>to>>col;
        add(to,i,1<<(col-'a')),add(i,to,1<<(col-'a'));
    }
    dep[1]=1,dfs_getson(1,-1),dsu(1,-1,true);
    for(register int i=1;i<=n;++i) printf("%d ",ans[i]);
    return 0;
}

おすすめ

転載: www.cnblogs.com/akura/p/11531192.html