ツリーCF 600EのDSU

トピックリンク:(CF)http://codeforces.com/contest/600/problem/E

     (ロス・バレー)https://www.luogu.com.cn/problem/CF600E

参考ブログ:(ツリーチェーン分割)https://www.cnblogs.com/zwfymqz/p/8094500.html#_label3_0

     (木のDSU)https://www.cnblogs.com/zcysky/p/6822395.html

第1のチェーンツリー分割のために、彼は2つの性質を持っています。

プロパティ1:もしエッジ(U、V)光側と、次いでサイズ(V)≤Size(U)/ 2 

プロパティ2:エッジの数の任意の2つのノード間のツリー経路が光log⁡nを超えない、パスの数は、重量LOGNを超えない

重パス2のプロパティを構成する連続した重い側を指しパス。

私は比較的あいまいな理解のための唯一の2のプロパティがあります。
    なぜなら自然1の存在のすべての最初に、私たちはこの結論を「ツリーライト側の数は、任意の2つのノード間のパス上にlog⁡nを超えていない」と結論付けることができます。
  我々は、点UのV側との間の光の点の数を計算すると仮定しているのでuはルートノードであり、この値がなければならない場合にVがリーフノードである場合、次に最も大きいです。
 すなわち、次の層に行く光側のUからVへの各付加的な経路は、U uを来る「UU」は、この側縁のは、次いで、U「は、サブツリーのサイズのルート光である未満か等しいサイズであろう( U)
/ 2
 この増加された光側は、サイズの初期値を作成することであった(U)は、2で割った、我々は、おそらく最初の部分2の性質のために来ることができます。 前半2の性質は、右、我々は実際に直接後半に導入することができるされている場合、すなわち、「任意の2つのノード間の重ツリーパスの数はlogN個を超えていない」、
軽鎖及び重鎖のエッジのパスは、互いにあるので接続パスは重量が、垂直方向の光の両側ことを理解すべき少数の例外を除いて当然の「サンドイッチ」、です。
だから、重い光パスの数と辺の数は、私たちが何をおよそ2 Aの性質を理解することができそうという、実質的に同じです。

この質問は、(LOS Valleyからの)タイトルを意図している:n個のノードを持つAツリーは、各ノードは、色の一種であり、各色は、ほとんどの各サブツリーの数、カラーコードツリー要求を有していますそして、。

アイデア:最初のDFSは重い息子のすべてのポイントを見つけ、サブツリーとカラーコードのほとんどをどこその後、各点について計算DFS:各サブルートノードのために、我々はまずそれを光サブツリーのすべての息子を計算ここで、我々は重い息子を排除していない光の仕上げ息子ごとに計算最大の色数とは、我々は彼の息子を持って、サブルートノードにこの光の影響を排除することができ、最終的に我々は、計算の終了後に再息子の値を計算します私たちは、この状態を保存したいので、の影響は、サブルートノードの値を計算するときにすることは繰り返すことができない、その重量を計算したら、どこサブツリーの値の息子。色の数に各点について計算し、最もそのサブツリートラバーサル時間を指示し、直前に出て算出され、それがもたらす影響を排除していないという理由だけで、サブツリー重いの息子さんをスキップします。これは、コードで直接見て非常に明確ではありません。

時間の複雑さはnlognです

#include <iostreamの> 
する#include <CStringの> 
する#include <アルゴリズム> 
の#include <キュー> 
の#include <マップ> 
の#include <スタック> 
の#include <cmath> 
の#include <ベクトル> 
の#include < セット > 
の#include <cstdioを> 
書式#include < 文字列 > 
の#include <デック> 
 使用して 名前空間はstdを、
typedefの長い 長いLL。
#define EPS 1E-8
 の#define INF 0x3f3f3f3f
 の#define MAXN 100005
 int型ヘッド【MAXN]、CNT、N-、M、K、T、
 INT カラー【MAXN]; 
 int型のTOT [MAXN]、息子[MAXN]; 
 INT ; NUM [MAXN]、Maxは、息子は// 最大メモリサブツリーを表示します見える色、息子格納されているサブツリー重い息子の最大数 
; LL SUM、ANS [MAXN] // 使用長いロングなお、ここで
ストラクトノード{
     int型、V、次に
エッジ[MAXN} * 2 ]、
 ボイドのinit( ){ 
    memsetの(頭、 - 1はsizeof (ヘッド)); 
    のmemset(SON、0はsizeof (SON)); 
    のmemset(NUM、0はsizeof (NUM)); 
    CNT =最大= SUM =0 ; 
} 
無効に追加する(INT U、INT {V)
    エッジ[ ++ CNT] .V = V、
    エッジ[CNT] .next = 頭部[U]; 
    頭部[U] = CNT; 
} 
ボイド DFS(INT U、INT PRE){ // ツリー息子の各点の計算重量 
    TOT [U] = 1 ;
     INT MX = - 1。;
     のためにINT Iは、ヘッド= [U];!私は= - 1 ;私は= エッジを[I] .next){
         int型 V = エッジ[I] .V;
         IF(V == PRE)続け
        DFS(V、U); 
        TOT [U] + = TOT [V];
         IF(MX < TOT [V]){ 
            MX = TOT [V]; 
            息子[U] = V; 
        } 
    } 
} 
無効に追加します(INT U、int型プリ、int型の OP){ // サブツリーのポイントの操作を追加し、減算、そこ加算および減算演算で同じではない、
                                // 全ての時点が低減される減算動作を追加重量シンク息子サブツリーのルート・ノード・スキップ 
    [カラー[U] = + NUMをOP;
     int型値= NUM [カラー[U]];
     IF(値> 最大){ 
        マックス= 値; 
        SUM = カラー[U]; 
    } そう IF(値== 最大){ 
        SUM + = カラー[U]; 
    } 
    ためINT Iは、ヘッド= [U];!私は= - 1 ;私は= エッジを[I ] .next){
         int型 V = エッジ[I] .V;
         IF(前|| V == V == ==息子&& OP 1// ここでバッチ操作のため、重い息子のサブツリーが付加されていません
        続行 ;                   // 以前のように重いの息子のサブツリーの影響排除しない   
        追加(V、U、OPを); 
    } 
} 
無効 DFS2(int型 U、int型プリ、int型のOP){
     ためINT I頭[U] =;!I = - 。1 ; Iは= エッジ[I] .next){
         int型 V = エッジ[I] .V;
         IF(Vは==事前||息子== V [U])続行; 
        DFS2(V、U、0 ); 
    } 
    IF (息子[U]){ 
        DFS2(SON [U]、U、1 ); 
    } 
    息子 =息子[U];      // 更新重いの息子、あなたが重い息子のサブツリーをスキップすることができたときにサブツリーの操作に加えて行うため、 
    アドオン(U、事前に、1); // 重い重量はこれだけ、息子の側面をスキップする場所の動作を追加操作に加えて、すべての光の息子のサブツリーを行い、
                 //光および各2点間のエッジの数はLOGN超えないので、そう各点について、回数が超えていないプラスLOGN動作は、動作は同様であり、以下の還元 
    ANS [U] = SUM。
    息子 = 0 ;         // 自重息子
    IF(OP == 0){     // 各光点間のエッジの数が2 logN個を超えないのでので、各点に対して、光息子のサブツリーの影響を排除、前記
                   // 回数それは引くだろう光のエッジでのみ、その祖先ノードので、LOGNを超えない減算を行う 
        追加の(Uは、予め、 - 1 ); 
        SUM = 0 ; 
        最大 = 0 
    } 
} 
int型のmain()
{ 
    一方(scanfの(" %のD "、およびN-)!= EOF){
        初期化(); 
        int型U、Vを、
        以下のためにINT iが= 1 ; I <= N; I ++ ){ 
            scanf関数(" %のD "、および色[I])。
        } 
        ためINT iは= 0、I <N- 1 ; I ++ ){ 
            scanf関数(" %D%D "、U、&&V)。
            (U、V)を追加。
            (V、U)を追加します。
        } 
        DFS(10 ); 
        DFS2(101);
        以下のためにINT iが= 1 ; I <= N; I ++ ){
             場合(I =!N)
            のprintf(" %のLLD " 、ANS [I])。
            
            のprintf(" %のLLD \ N " 、ANS [I]); 
        } 
    } 
    戻り 0 
}

おすすめ

転載: www.cnblogs.com/6262369sss/p/12152673.html