この問題の理論に対する最適解
効果の件名:サブツリーを合計し、パスを変更します
明らかに、テンプレートツリーのセクションが、クロスの木の時間複雑高アップ卓越した$ \シータ(Q \;ログイン ^ 2N)$、 実際に木の差が時間複雑$ \シータに置くことができます(Qを\; LOGN)$。
全ての値に設定$タグ[X] $ 1~ $ X $ $ $パスは、追加明らかに $(x、y)との$ Dの$このパスを追加操作$とみなすことができる
$$タグ[X] + = D、タグ[Y] + = D、タグ[LCA(X、Y)] - = D、タグ[PRT [LCA(X、Y)]] - = D $$
木と子の$ルート$ルートのクエリは、回答のサブツリー内の各点$ xには$の寄与を考慮した場合である
(DEP [X] -dep [$$ルート] +1)\回タグ[X] $ $の
式センスポイントは、すべて$タグが追加される(X、根)$パス$ある[X] $、加算したタイプの
$$ \和\を、((DEP [X] - DEP [ルート]さんが+1)\タイムズタグ[X])$$
$$ \ SUM \;(DEP [X] \タイムズタグ[X] - (DEP [ルート] -1)\タイムズタグ[X])$ $
$$ \ SUM \;(DEP [X] \タイムズタグ[X]) - (DEP [ルート] -1)\タイムズ\ SUM \;(タグ[X])$$
二フェンウィックツリーのメンテナンス$のDEP [X]回タグ\ [X] $と$タグ順序$ DFS $サブツリーに連続した範囲、直接クエリであるため、[X] $は、良いです。
私はあまりにも醜いコードが一定であるだから、理論的な最適解はツリーセクションとして良い実行する必要があります
#include <iostreamの> する#include <iomanip> の#include <CStringの> する#include <cstdioを> する#include <cmath> の#include <アルゴリズム> 使用して 名前空間STDを、 #defineは長いlong int型 インラインint型(){読み取り チャーCH。 BOOL BJ = 0 。 しばらく(!isdigit(CH = getchar関数())) BJ | =(CH == ' - ' ); INT RES = CH ^(3 << 4 )。 一方、(isdigit(CH =GETCHAR())) RES =(RES << 1)+(RES << 3)+(CH ^(3 << 4 ))。 リターン?BJ - 解像度:解像度。 } ボイド printnum(INT X){ 場合(X> 9)printnum(X / 10 )。 putchar(Xの%10 + ' 0 ' )。 } インラインボイドプリント(INT X、チャーCH){ 場合(X < 0 ){ のputchar(' - '); X = - X。 } printnum(X)。 putchar(CH)。 } のconst int型 MAXN = 1E5 + 5 。 INTのN、M、H [MAXN]、CNT。 INT TOP [MAXN]、サイズ[MAXN]、PRT [MAXN]、息子[MAXN]、DEP [MAXN]、TOT、TID [MAXN]。 構造体のエッジ{ INT 、NXTに、 } [MAXN W << 1 ]。 INT C1 [MAXN]、C2 [MAXN]。 インラインボイド AddEdge(int型のx、int型のY){ [W = .nxt ++ CNT] H [X]。 W [CNT] .TO = Y。 H [X]= CNT。 } ボイド DFS1(int型のx、int型 FA、int型の深さ){ DEP [X] = 深度。 PRT [X] = FA。 サイズ[X] = 1 。 以下のために(int型 I = hの[X]; I; I = W [i]は.nxt){ int型、V = W [i]は.TO。 もし(== FA V)続けます。 DFS1(V、X、深さ + 1 )。 もし(サイズ[V]>サイズ[息子[X]])息子[X] = V。 サイズ[X] + = サイズ[V]。 } } ボイド DFS2(int型のx、int型SP){ トップ[X] = SP。 TID [X] = ++ TOT。 もし(息子[X]!)を返します。 DFS2(息子[X]、SP)。 以下のために(int型 I = hの[X]; I; I = W [i]は.nxt){ int型、V = W [i]は.TO。 もし(V == PRT [X] || V ==息子[X])続けます。 DFS2(V、V); } } インラインINT LCA(int型のx、int型のY){ 一方(上面[X] ^ トップ[Y]){ もし(DEP [TOP [X] < DEP [トップ[Y])スワップ(X、Y) X = PRT [TOP [X]]。 } もし(DEP [X]> DEP [Y])スワップ(X、Y) リターンのx; } インラインINT lowbit(INT X){ 戻り X&( - X)。 } インラインボイド更新(int型のx、int型 D、INT C []){ 場合(!X)のリターン; 一方、(x <= N)C [X] + = D、X + = lowbit(X)。 } インラインINTクエリ(INT X、 int型C []){ int型の和= 0 。 一方、(X)の和+ = C [x]は、x軸= lowbit(X)。 戻り値の合計。 } インラインボイド追加(int型のx、int型D){ 更新(TID [x]は、D、C1)。 アップデート(TID [x]は、DEP [X] * D、C2)。 } インラインINTは(ASK int型のx、int型、YをINT C []){ 戻りクエリ(Y、C)-query(X- 1 、C)。 } {main()の符号付き のN = 読み取ります()。 INTX、Y、D。 以下のために(int型 i = 1 ; iがn <; iは++ ){ X =リード()+ 1 。 Y =リード()+ 1 。 AddEdge(X、Y) AddEdge(Y、X)。 } DFS1(1、0、1 )。 DFS2(1、1 )。 M = 読み取ります(); char型のCH; 一方、(M-- ){ DO CH = GETCHAR()。 しばらく(CH!= ' A '!&& CH = ' Q ' ); もし(CH == ' A ' ){ X =リード()+ 1 。 Y =リード()+ 1 。 D = 読み取ります(); INT U = LCA(X、Y) (X、D)を加えます。 (Y、D)を加えます。 (、Uを追加 - D)。 追加(PRT [U]、 - D)。 } 他{ X =リード()+ 1 。 INT TMP =尋ねる(TID [x]は、TID [X] +サイズ[X] - 1、C1)。 プリント(ASK(TID [x]は、TID [X] +サイズ[X] - 1、C2)-tmp×(DEP [X] - 1)、' \ n ' ); } } 戻り 0 。 }
なぜ2つのDFSが書かれていましたか?私は木のセクションLCAをお願いしたいと思いますので、