$ U $のパス上のノードへのプレイヤーのパス$(x、y)は$の貢献を考えてみましょう
$のDEP [X] -dep [U]はW = $のLCA = LCA(x、y)は$、$ U $チェーン$ Xを、LCAの$、経路生成貢献$ 1 $もし設けられている場合にのみ[ U] $
前記$のDEP [i]は$ $ I $は$ wは、ノードの深さを示し、[I] $対象が$ Wの$与えられ、すなわち、式$のDEP [X] DEP [U]を= + W [U] $
場合チェーン$ U $ LCAの$、$ Yパスが生成される$ DEPの寄与場合に限り、[Y] -dep [U] = DIS(x、y)は、[U] $を-w
$ DIS(X、Y)の$ X、Yの$経路長、すなわち、式$のDEPを表す$ノード[Y] -dep [U] = DEP [X] + DEP [Y] -2dep [LCA] -w [U] $
$ -dep即[X] + 2dep [LCA] = DEP [U] [U] $を-w
ダイレクトリンクツリー分割し、各セグメントツリーの深さは、$ X $ $ $ Yに、パス$(x、y)は$セグメントは、ツリーの深さに直接対応するために、上記の二つのケースを別々に維持するために、動的開口点を維持しますすべてのノード$ 1 $ +
その深さは、これは両方の場合では、2つのセグメントの各々の深さは別々のツリーを維持すべきであることに注意し、[X] $と$ -depの深さ[X] + 2dep [LCA] $ $ DEPであります
後者の場合は、負の深さを持っている可能性があるため、深さはN $がプラスに変わる$となり、$ 2dep [LCA] -dep [X追加する必要があります ] + N $を、 そして$ LCAの$になりそうするように注意を払います減らすために1回、2回カウント
U $ $クエリノード場合DEP $へのクエリの深さ[U] + W [U] $と$ DEP [U] -w [U] + N $(ノート$ + N $)セグメントツリーノードU $ $以下のような値
ツリーラインのノードの最大数は、良好なノート、永久的な、音声及び高速書込み速度でマークされたコードセグメントツリー考慮すべき
#include <iostreamの> する#include <cstdioを> する#include <アルゴリズム> の#include <CStringの> する#include <cmath> の#include <地図> 使用して 名前空間STD。 インラインint型リード() { int型のx = 0、F = 1。チャー CH = GETCHAR()。 一方、(CH < ' 0 ' || CH> ' 9 '){ 場合(CH == ' - ')、F = - 1。CH = GETCHAR()。 (CH> = ' 0 ' && CH <= ' 9 '){X =(X << 1)+(X << 3)+(CH ^ 48)。CH = GETCHAR()。} 戻りのx *のF。 } のconst int型 N = 3E5 + 7 。 INTのN、M、W [N]。 INT、FIR [N] から [N << 1 ]、[N <<に1 ]、CNTT。 インラインボイドは(追加INT A、INT B){ から [A] [++ CNTT] =モミ。FIR [A] = CNTT。【CNTT] =用にB。} INT RT1 [N <<1 ]、[N <<のRT2 1 ]、T [N * 40 ]、L [N * 40 ]は、R [N * 40 ]、タグ[N * 40 ]、CNT; // セグメントツリー更新でRT1のU (X、LCA)は、セグメントツリーのメンテナンスU(LCA、Y)RT2 空隙 INS(INT&O、int型の L、INT R&LT、INT QL、INT QR、INT K)を { IF(!O)O = ++ CNT; IF(L> = QL && R&LT <= QR){タグ[O] + = K; 返す;} int型 MID = L + R&LT >> 1 ; IF(QL <= MID)INS(L [O] 、L、MID、QL、QR、K); IF(MID <QR)イン(R [O]、ミッド+ 1 、R、QL、QR、K)。 } INTクエリ(INT&O、int型の L、int型の R、int型のPOS) { もし(O!)戻り 0 ; もし(L == R)戻りタグ[O]。 INT半ば= L + R >> 1 。 リターン(?POS <=中間クエリ(L [O]、L、中間、POS):クエリ(R [O]、ミッド+ 1、R、POS))+ タグ[O]。 } int型の息子[N]・FA [N]、SZ [N]、DEP [N]、上位[N]、ID [N]、dfs_clock。 ボイド DFS1(INT X) { SZ [X]= 1 ; 以下のために(int型 [X] I =モミ; I; I = から[I]) { int型&V = [I]であり; もし(V == Faが[X])続けます。 FA [V] = xと; [X] + [V] = DEP DEP 1。DFS1(V); SZ [X] + = SZ [V]。 もし(SZ [V]> SZ [息子[X]])息子[X] = V。 } } ボイド DFS2(int型のx、int型のTP) { ID [X] = ++ dfs_clock。トップ[X] = TP。 もし(息子[X])DFS2(息子[x]は、TP)。 以下のために(int型 I = FIR [X]; I; I =[I]) { int型&V = [I]であり; もし(V == Faを[X] || V ==息子[X])続けます。 DFS2(V、V); } } int型 LCA(int型のx、int型のY) { ため(; TOP [X] = TOP [Y];!X = Faを[TOP [X]]) であれば(DEP [TOP [X] < DEP [TOP [ Y])スワップ(X、Y) 戻り DEPを[X] <DEP [Y]?X:Y。 } // DEP [X] -dep [U] == W [U] DEP [Y] -dep [U] == DEP [X] + DEP [Y] -2dep [LCA] -w [U] // [U] -dep W [U] + [X] == DEP DEP [X] + 2dep [LCA] == DEP [U] -w [U] ボイドワーク(int型のx、int型Y) { int型 LCA = LCA(x、y)は、P。 用(; TOP [P] = TOP [LCA]!P = P = X Faを[TOP [P]) イン(RT1 [DEP [X]、1、nは、ID [TOP [P]、ID [P]、1 )。 イン(RT1 [DEP [X]、1、nは、ID [LCA]、ID [P]、1 )。 用(!P = Y; TOP [P] = TOP [LCA]; P = Faを[TOP [P]) イン(RT2 [ 2 * DEP [LCA] -dep [X] + N]、1、nは、 ID [TOP [P]、ID [P]、1 )。 イン(RT2 [ 2 * DEP [LCA] -dep [X] + N]、1、nは、ID [LCA]、ID [P]、1 )。 イン(RT1 [DEP [X]、1、nは、ID [LCA]、ID [LCA]、 -1); // 注意LCA被算了两次 } INT (メイン) { N =(読み取り)、M =読み取ります(); int型、B; 以下のために(int型 I = 1 iは++; iがn <が) { =(リード)、B = )(読み取ります。 追加(A、B)。(B、A)を加えます。 } のための(int型 I = 1を W [I] = iが++; iが<= N) )(読み取ります。 DEP [ 1 ] = 1。DFS1(1)。DFS2(1、1 )。 以下のための(int型私は=1 ; I <= M; iは++)A =リード()、B = 読み取る()、ワーク(B) 以下のために(int型 i = 1 ; iが<= N; iは++ ) { int型 ANS1 =クエリ(RT1 [DEP [I] + W [I]、1 、nは、ID [I])。 INT ANS2 =クエリ(RT2 [DEP [I] -w [I] + N]、1 、nは、ID [I])。 printf(" %dの"、ANS1 + ANS2)。 } 戻り 0 。 }