ロールバックツリーDP(DPによってDFS順) - hdu6035

このトピックの別のブログで動作しています。難易度は、DFSへの答えを見つける方法、色CIの貢献であります

別に私はDFSで計算されて着色する方法を最初に考えてみましょう

  深い検索処理において、DFSトラバーサル順序方法を使用して、色付きヒットポイントI U、Uの各色iはリンクブロックの寄与ではない子ノードvであり、

  V寄与ユニコムブロックサイズがサイズである[V] -sum {ノードに最高レベルのV iはサブツリー根ざしサイズの色です}

  その後、我々は最初のiをvに根ざした部分木の大きさであるノードへの色の最高レベルを取得する必要があり、それは、最後に、vはDFSの前に金額を入力して保存することができ、これまでのカラーI和とすべてのサブ木の大きさを表し、即ち、合計がIカラーの下のサブツリーvがない場合

  VのDFSに移動し、合計でサブツリーのサイズに追加

  すべてのサブツリーが横断してVの後、我々は合計-最後のノードiがレベルvをルートとするサブツリーのサイズで色が最高であることがわかります

  (和最後) - 次いで、VユニコムブロックサイズはK =サイズ[V]であり、寄与

  そして、Vへのuのサブツリーは、「Uのすべてのサブツリーを経て完成するまで、この時点では、カラーで(uは含まれません)Uまでの合計値となっている私は、ルートとするサブツリーのサイズで同じ操作を実行しますと

  Uに色の私の祖先を計算するには、uのに必要なもの和に組み込まれ、そしてUは合計のみで独自に追加する必要があり、加えて聯通のブロック全てがVに貢献

  情報は現在、情報のメンテナンスのすべてを完了した、uが祖先ノードバックアップのuをロールに決定、DFSを起動することができます

再び最初のDFSに表示されるすべての色を計算する方法を検討し、

  我々は、需要の各色は、あなたができ、Cへの和の代表の色を維持するために、[C]配列和を使用し、サイズ[]、並びに和に対応する各色を用い寄与、上記再帰に見出すことができますメンテナンスは、DFSにおけるさまざまな色に貢献します

この質問と虚ツリーやや似た場所、最初の各色が課題であるとして、それは尋ねた仮想ツリーに似ています

その後、プロセスは、葉までの需要から、DFSにロールバックされます(DFS順序に従って、実際には)、uがDFSたときに最初に遭遇した時の前の状態への記録状態をDFSとその子ノードのすべてを処理し、Uを計算する:により、状態

#include <ビット/ STDC ++ H> 
の#include <ベクトル>
 使用して 名前空間STDを、
#define MAXN 200005 
 の#defineっ長い長

LL ANS、色[MAXN]、サイズ[MAXN]和[MAXN]。
ベクター < INT > G [MAXN]。

ボイド DFS1(int型 U、int型のPRE){ 
    サイズ[U] = 1 以下のためにint型 i = 0 ; iは、Gを<U] .size(); iは++ ){
         int型、V = G [U] [I]。
        もし(V ==前)続けます
        DFS1(V、U);
        サイズ[U] + =サイズ[V]; 
    } 
} 

// これは、SUM []配列の意味を理解する最も重要な木のDPで、合計[x]はリーフノードから仮想イメージ囲まツリーを更新するロールバックと同じです 
ボイド DFS2(INT U、INT PRE){ 
    LL OTHER = 0 ; // [U] U全てが最高の色で減算[U]は根の大きさであるように、他の大きさが表現される
    ためint型 I = 0 Iの<。 G [U] .size();私は++ ){
         int型 V = G [U] [I];
         IF(V == PRE)続行; 
        LL最終 = SUM [カラー[U]]; // レコードフロントサブツリー前サブツリーuが色の値である(仮想ツリー)
        DFS2(V、U); 
        差分LLSUM = [カラー[U]] -最終; // の番号vのサブツリーの色のカラー[U]
         // Vツリーは、ブロックサイズの色を[U]は含まれませんユニコム 
        ANS + =(サイズ[V] -diff- 1)*(サイズ[V] -diff)/ 2 ; 
        OTHER + =サイズが[V] - 差分; 
    } 
    SUM [色[U] + = OTHER + 1 ; // + +1色自体Uため[U] 
}
 int型F [MAXN]、TOT;
 int型のmain(){ 
    T、N- LL = 0 ;
     一方(CIN >> N-){
         ++ T;
         のためのINT I = 1 ; I <= N; I ++は) G [i]が.clear();
        memsetの(F、0sizeof f)は、
        TOT = 0 ; 
        
        以下のためにint型 i = 1 ; iが<= N; iが++ ){ 
            scanf関数(" %dを"、および色[I])。
            F [色[I] = 1 
        } 
        のためのint型 i = 1 ; iが<= N; iが++)TOT + = F [i]は、
        以下のためにint型 i = 1 ; iがn <; iは++ ){
             int型Uを、V。
            scanf関数(" %d個の%d個"、&​​U&V);
            G [U] .push_back(V)。
            G [V] .push_back(U)。
        }         
        
        もし(TOTの== 1 ){ 
            のprintf(" ケース#1%のD:%LLDする\ n "、T、N *(N- 1)/ 2 )。
            続け; 
        } 
        
        のmemset(サイズ、0はsizeof サイズ)。
        memset(和、0はsizeof 合計)。
        
        ANS = 0 ; 
        DFS1(11); DFS2(11 )。
        にとってint型 i = 1 ; iがn = <; iは++ 場合([i]がF)
                ANS + =(N-和[I])*(N-和[1] - 1)/ 2 
        LLのTMP =(N- 1)* N / 2 *のTOT。
        printf(" ケース#%dを:%LLDの\ nを"、トン、tmp- ANS)。
        
    } 
}

 

おすすめ

転載: www.cnblogs.com/zsben991126/p/11200539.html