このトピックの別のブログで動作しています。難易度は、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、0、sizeof 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(1、1); DFS2(1、1 )。 にとって(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)。 } }