質問の意味:木を考えると、$ M $の操作があります。
操作0:$、$重量はS $ $(p、q)を添加パスに設定されている$ V $
操作1:$ V_を{生成し、右$ T $とセットで求め、パス$ I $および$ T $交差する場合、である(交差点を有し、$ S $路、点$ T $のセットが与えられますI} $の貢献)
データ範囲:路長$ \ leqslant 20 1 \ leqslant N $、$、M \ leqslant 10 ^ 5 $
パスの長さが0(すなわち、$ $ S全ての点)との言葉であればツリーと右のチェーンは、$ T $のポイントの私達のセットを見つけることです。
DFSは、オーダー+フェンウィックツリーを維持するために使用することができます。
任意の2点間のツリーが$ I $のポイントはその後、$ I-1 $エッジを通過します後場合という重要な特性は、エッジの数は常にポイントです-1。
そして、次のステップは、特に神です。
新しく追加されたパスの場合:重みプラス重みの反対側に追加経路上の点。
あなたはこのブロックからの通信経路を検索し、設定した場合には、ポイントと$ I $ $ I-1 $エッジを経過している必要があります。
1のみの寄与効果一旦達成さ - つまり、エッジ点の一定の数に等しいです。
右は、ルートと、我々はDFS順+ツリーの配列を使用する方法にポイントを維持するために。
#include <ベクトル> の#include <cstdioを> する#include <設定> の#include <CStringの> する#include <ストリング> の#include <アルゴリズム> の#define N 200007 の#define長い長llの 名前空間stdを使用。 ボイドsetIO(文字列s){ = S +の文字列"に"。 = S +アウト文字列"アウト。"; freopenは(in.c_str()、 "R"、標準入力)。 freopenは(out.c_str()、 "W"、STDOUT)。 } 構造体BIT { LL C [N]。 INT lowbit(INT T){ 戻りT&( - T)。 } ボイド更新(int型のx、int型V){ 一方(X <N){ C [X] + =(LL)V。 X + = lowbit(X)。 } } } LLクエリ(INT X){ LL TMP = 0。 一方、(X> 0){ TMP + = C [X]。 X- = lowbit(X)。 } TMP返します。 } }木。 int型TOT; 整数N、M、L。 int型のエッジ; int型DFN; int型のHD [N]。 [N << 1]〜INT。 INT NEX [N << 1]。 INTトップ[N]。 int型の息子[N]; INTサイズ[N]。 INTのDEP [N]。 INT A [N]。 INT FA [N]。 int型ST [N]; int型のED [N]; INT Faを[N]。 ベクター<INT> G [N]。 ブールCMP(int型B、INTは){ ST [] <ST [B]を返します。 無効アドオン(int型のu、int型のV){ NEX [++エッジ] = HD [U]。 HD [U] =縁。 [エッジ] = Vまで; } ボイドDFS1(INT U、INT FF){ FA [U] = FF。 サイズ[U] = 1。 DEP [U] = DEP [FF] +1。 {(; iはNEX [I] = [U] INT I = HD)用 のint = Vに[I]を、 (V == FF)場合{ 続けます。 } DFS1(V、U)。 サイズ[U] + =サイズ[V]。 IF(サイズ[V]>サイズ[息子[U]]){ 息子[U] = V。 } } } ボイドDFS2(INT U、INT TP){ トップ[U] = TP。 IF(息子[U]){ DFS2(息子[U]、TP)。 } {(; iはNEX [I]を= [U] INT I = HD)用 (![I] = FA [U] &&に[I] =息子[U]へ){場合 DFS2([I]に、に[I])。 } } } int型LCA(int型のx、int型のY){ 一方(上面[X]!= TOP [Y]){ DEP [トップ[X]]> DEP [トップ[Y]]?X = FA [トップ[X ] Y = FA [トップ[Y]。 } 戻りDEP [X] <DEP [Y] X:Y;? } //到根的权和 LL和(INT X){ 戻りtree.query(ST [X])。 } ボイドビルド(INT U){ ため(INT I = HD [U]; iは、iはNEX [I] =){ int型V =に[I]を、 (V == FA [U])であれば{ 続けます。 } ++ TOT。 FA [TOT = U。 FA [V] = TOT。 G [U] .push_back(TOT)。 G [TOT] .push_back(V)。 (v)を構築します。 } } ボイドDFS(INT U){ ST [U] = ++ DFN。 以下のために(; I <G [U] .size(); INT iが0 = ++ I){ int型、V = G [U] [I]。 //のprintf( "%D%D \ n"は、U、V)。 DFS(V); } ED [U] = DFN。 } int型のmain(){ setIO( "木")。 私は、jはint型。 scanf関数( "%D%D%D"、&N、&M&L)。 ため(I 1 =、iは<N; ++ I){ int型のX、Y。 scanf関数( "%D%D"、およびX&Y)。 (x、y)を加えます。 (Y、X)を追加します。 DFS1(1,0)。 TOT = N。 ビルド(1); DFS(1)。 (M--){一方 INT OP。 scanf関数( "%のD"、&OP)。 IF(OP == 0){ int型のP、Q、V、D = 1。 scanf関数( "%D%D%D"、&P、およびQ&V)。 INT LCA = LCA(P、Q)。 一方、(P = LCA!){ tree.update(ST [P]、D * V)。 tree.update(ED [P] + 1、-d * V)。 D * = - 1; P = Faを[P]。 } 、D = 1。 一方、(!Q = LCA){ tree.update(ST [Q]、D * V)。 tree.update(ED [Q] + 1、D * V)。 D * = - 1; Q = Faを[Q]。 } tree.update(ST [LCA]、V)。 tree.update(ED [LCA] + 1、-v)。 } 他{ int型、CNT = 0。 scanf関数( "%のD"、&)。 {(; I <= A ++ iは= 1)のため のscanf( "%dの"、&A [++ CNT])。 } のscanf( "%d個"、&)。 {(; I <= A ++ iは= 1)のため のscanf( "%dの"、&A [++ CNT])。 } ソート(A + 1、A + 1 + CNT、CMP)。 INT LCA = A [1]。 以下のために(I 2 =、iは<= CNT; ++ I){ LCA = LCA(LCA、A [I])。 LL ANS = 0。 {(++ I; I <= CNT I = 1の)のための ANS + =合計(A [I]) -合計(FA [LCA])。 } (iは2 =; I <= CNT; ++ i)に対する{ ans- =合計(LCA(A [i]が、A [I-1])) -合計(FA [LCA])。 } のprintf( "%のLLD \ n"は、ANS)。 } } 0を返します。 }