トピックリンク:http://codeforces.com/problemset/problem/600/E
あなたは、頂点のルートとルート権限を取得し、ツリー与えられている 1。各頂点は、いくつかの色に着色されています。
レッツ・コール・カラー C 頂点のサブツリーに支配 V の頂点のサブツリーに表示され、他の色が存在しない場合は 、V カラーよりも多くの時間 cが。だから、2色以上は、いくつかの頂点のサブツリーに支配されている可能性があります。
頂点のサブツリー Vは 頂点である V 頂点含まれており、他のすべての頂点 Vを ルートへの各パスに。
各頂点について V 頂点のサブツリー内のすべての支配的な色の合計見つけ Vを。
入力
最初の行は整数含ま N (1≤ N ≤10 5) -ツリー内の頂点の数。
2行目は含ま nは 整数 C I (1個の≤ C I ≤ N)、 C I -の色 I番目の頂点。
次の各 N - 1行は、二つの整数含ま X J、 Y J (1≤ X 、J、 Y J ≤ Nツリーのエッジ- )。最初の頂点は、ツリーのルートです。
出力
印刷 nは 整数-各頂点の色を支配の合計。
例
入力
4
1 2 3 4
1 2
2 3
2 4
出力
10 9 3 4
入力
15
1 2 3 1 2 3 3 1 1 3 2 2 1 2 3
1 2
1 3
1 4
1 14
1 15
2 5
2 6
2 7
3 8
3 9
3 10
4 11
4 12
4 13
出力
654,323,311,322,123
タイトル効果:入力N、N個のノードがあり、Nは、各ノードの次の色の数、次のN-1行、各2を表し木であることが保証それらの間の代表UVエッジの数は、根の規定は1である
ルート、最大の色数やどのくらいの値の出現である各ノードにあなたを求める、(数が数値として表示されることがありますそしてより多くの)
アイデアは:それは、読んで私は、ツリーのマージの、あまりにも多くの作品を望んでいた時に質問を補うために時間を持っていなかった時間をプレイし、完全にボードのタイトルのセグメントツリーの合併であるが、そのタイムアウトは、彼らが書き込み、問題への解決策を参照し、そのツリーラインのマージが見つかりませんでした
ここでnはノードおよびMが存在すると仮定すると、範囲の複雑で、複雑である:O(nlogm + N)、重量寄与である私にはわからないことを証明するために
コードを見て:
#include <iostreamの> する#include <CStringの> する#include <アルゴリズム> の#include <cstdioを> 使用して 名前空間をSTD。 typedefの長い 長いLL。 #define LSON TR [今] .L の#define rson TR [今] .R CONST INT MAXN = 1E5 + 5 。 const int型 MAXM = 50 ; LL N; LL CNT = 0、NUM = 0 。 LL [MAXN]。 LLヘッド【MAXN]。 LLルート[MAXN]。 LL ANSS [MAXN]。 構造体のエッジ { 、NXTへのLL。 } E [MAXN << 1 ]。 構造体の木 { L LL、R&LT、SUM、ヴァル、ANS; // 左の子、色の数、この場合の値対応する回答 } TR [<< MAXN 5。]; ボイドadd_edge部材(LL U、V LL) { E [ ++ CNT] .TO = V。 [CNT] .nxtへ = ヘッド[E]。 ヘッド[U] = CNT。 } 空Push_up(今LL) { IF(TR [LSON] .SUM> TR [rson] .SUM)// 最も左の部分木の数 { TR [今] .ans = TR [LSON] .ans。 TR [今] .SUM = TR [LSON] .SUM。 TR [今] .val = TR [LSON] .val。 } IF(TR [LSON] .SUM <TR [rson] .SUM)// 右サブツリー内の左端の数 { TR [今] .ans = TR [rson] .ans。 TR [今] .SUM = TR [rson] .SUM。 TR [今] .val = TR [rson] .val。 } IF(TR [LSON] == .SUM TR [rson] .SUM)// 最も左及び右サブツリーの数 { TR [今] .ans = TR [LSON] .ans + TR [rson] .ans; // 答えはの和である TR [今] .SUM = TR [LSON] .SUM; // 定数の数 TR [今] TR = .val [LSON] .val; // 値は問題ではありません } } LLマージ(LLのX、LLのY、LLのL、LLのR) { IF(!X)は戻り Yを; // 他の自体を空の数は確実に合成された後、 IF(Y!)戻りX; IF(R&LT == L)// リーフノードに { TR [X] .SUM + TR = [Y] .SUM; // 更新と .ans TR = [X] L。 T R [X] .val = L。 戻り値は、X; } LLミッド =(L + R)>> 1 。 T R [X] .L = マージ(TR [X] .L、TR [Y] .L、L、MID)。 ARR [X] .R =マージ(ARR [X] .R、TR [Y] .R、中間+ 1 、R)。 Push_up(X)。 戻り値は、X; } 空アップデート(LL&今、LLのL、LL R、LL POS、LL V) { IF(今!)今NUM = ++; // ノートですNUMの初期値N IF(L == R&LT) { TR [今] .SUM + = V。 TR [今] .ans = L。 TR [今] .val = L。 リターン; } LLミッド =(L + R)>> 1 。 もし(POS <= MID)更新(LSON、L、中間、POS、V)。 他の更新(rson、ミッド+ 1 、R、POS、V); Push_up(今)。 } 空DFS(LLのX、事前LL) { 用(;! - I = iはヘッド[X] = LL 1 ; iが= Eを[I] .nxt) { LLのV = E [I] .TO。 もし(V ==前)続けます。 DFS(V、X) マージ(ルート[X]、根[V]、1、N); //はそれ自身を置くと、そのサブツリーはマージ } アップデート(ルート[X]、1、N、A [X]、1。); // ノード自体は、それほど更新得るために、値を有する ANSS [X] = TR [ルート[X]]; ANS } int型のmain() { scanf関数(" %のLLD "、&N)。 NUM = N。 以下のために(INT iが= 1 ; I <= N; I ++ ) { scanf関数(" %のLLD "、および[I])。 ルート[I] = I; // の各ツリーノードに相当する ヘッド[I] = - 1。 。 } 用(INT iは= 1、I ++; I <N ) { LL U、V; scanf関数(" %LLD%LLD "、U、&&V)。 add_edge(U、V); add_edge(V、U)。 } DFS(1、0 ); 以下のために(INT iが= 1 ; I <= N; I ++)のprintf(" %のLLD "、ANSS [I]); COUT << ENDL。 リターン 0 ; }