トピックへのリンク:https://www.luogu.org/problem/P3833
タイトル効果は:を含むツリーは、各ノードが最初に0は、次の2回の操作で、N個のノードを有します。
1.AddのUVDは、UとVとの間の経路上の全てのノードの値を表すプラスDです。
2.Query uがuは、サブツリー、どのように多くの合計のフルーツを根ざしポイントに、現在の果樹を表し?
ソリューションの概要:連鎖スプリット木板、特にコードのコメントを参照するには
コード:
#include <ビット/ STDC ++ H.> 使用して 名前空間STD; typedefの長い ロング; LL のconst int型 MAXN = 100005 ; int型のTOT、CNT、ヘッド【MAXN]は、N-、M、V [MAXN]; LLツリー[MAXN * 4 ] 、怠惰な[* MAXN 4。]; int型のD [MAXN]、サイズ[MAXN]、息子[MAXN]、ID [MAXN]、RK [MAXN]、FA [MAXN]、トップ[MAXN]; // サイズ[I]サブツリーのノードの番号i、トップ[i]はiは、重鎖の上面であり、息子[i]はiが重い息子の数である // D [i]は、ノードの真の深さは、Iであり、ID [i]はiは新しい番号、FA [i]は番号iの父親である 構造体のエッジ{ int型、V、次に エッジ} [MAXN << 1。]; 無効(ADDをINT U、int型V){ エッジ[TOT] .V = V、 エッジ[TOT] .next = 頭部[U]; 頭部[U] = TOT ++ ; } ボイド DFS1(INT U、INT PRE){ // 最初のDFSは、各ノード、親ノード、サブツリーの大きさの深さにわたって求めて D [U] = D [事前] + 。1 ; FA [U] = 予備; サイズ[U] = 1 ; のための(int型 I =頭[U ] ;! = I - 1 ; I = エッジ[I] .next){ int型 V = エッジ[I] .V; IF(V =! PRE){ DFS1(V、U); サイズ[U] + = サイズ[V]; IF(サイズ[ソン[U] <サイズ[V])の息子[U] = V; } } } ボイド DFS2(INT U、INT TP){ // 重鎖の各新しいノード番号と重量を見つける場所トップと息子 トップ[U] = TP、ID [U] = CNT ++、RK [CNT] = U; IF (息子[U])DFS2 (息子[U]、TP); // 重鎖への連続的な重鎖上の全てのノードは、セグメントツリー情報によって維持され得ることを確実にするため、DFS開始及び再子ノード のために(int型 I =ヘッド[U];私は!= - 1 ; I = エッジ[I] .next){ int型 V = エッジ[I] .V; IF(V FA = [U] = V &&!息子[U])DFS2(V、V)。 } } ボイド押し上げ(int型RT){ ツリー[RT] =ツリー[RT << 1 ] +ツリー[RT << 1 | 1 ]。 } ボイドプッシュダウン(int型 L、int型の R、int型RT){ 場合(怠惰[RT]){ ツリー[RT << 1 ] =ツリー[RT << 1 ] +怠惰[RT] * L。 ツリー[RT << 1 | 1 ] =木[RT << 1 | 1 ] +怠惰[RT] * R。 怠惰な[RT <<1 ] + = 怠惰[RT]。 怠惰な[RT << 1 | 1 ] + = 怠惰[RT]。 怠惰[RT] = 0 ; } } ボイドビルド(int型 L、int型の R、int型RT){ 怠惰[RT] = 0 ; もし(L == R){ ツリー[RT] = V [RK [L]]。 返します。 } INT半ば= L + R >> 1 。 構築(リットル、ミッド、RT << 1 )。 (半ばを構築 +1、R、RT << 1 | 1 ); 突き上げ(RT)。 } ボイド更新(int型 L、INT R、int型のVal、INT L、INT R、INT RT){ 場合(L <= 1 && R> = R){ ツリー[RT] + = 1LL *(R-L + 1 *)のVal ; 怠惰[RT] + = ヴァル。 返します。 } INT半ば= L + R >> 1 。 プッシュダウン(MID -l + 1、R- 半ば、RT)。 もし(MID> = L)更新(L、R、ヴァル、L、中間、RT << 1 )。 もし(MID <R)更新(L、R、ヴァル、中間+ 1、R、RT << 1 | 1 )。 突き上げ(RT)。 } LLクエリ(int型 L、INT R、int型の L、INT R、INT RT){ 場合(L <= 1 && R> = R)戻りツリー[RT]。 INT半ば= L + R >> 1。LLのRES = 0 。 プッシュダウン(MID -l + 1、R- 半ば、RT)。 もし(MID> = L)RES + =クエリ(L、R、L、中間、RT << 1 )。 IF(MID <R&LT)RES + =クエリ(L、R&LT、MID + 。1、R&LT、RT << 1 | 1 ); 戻り、RESを } ボイド更新(int型のx、int型の yは、int型 {ヴァル)を// yにXを変更します最短経路の値 一方(TOP [X]!= TOP [Y]){ // 最大ジャンプしない同一の重鎖 IF(D [TOP [X] < D [TOP [Y])スワップ(X、 Y)、 更新(ID [TOP [X]、ID [X]、ヴァル、1、N-、1。); X = FA [TOP [X]]; // 親ノードの重鎖の上部へのジャンプ } IF(ID [X]> ID [Y])スワップ(X、Y); //二つの同一の重鎖内のノードが、同じノードではないかもしれない 更新(ID [X]、ID [Y]、ヴァル、1、N - 、1 ); } ASK 11(int型の Xを、int型 Y){ // クエリX Yの最短パス値 LL RES = 0 ; ながら(!TOP [X] = TOP [Y]){ IF(D [TOP [X] < D [TOP [Y])スワップ(x、y)は; RES + =クエリ(ID [TOP [X]、ID [X]、1、N-、1。); X = FA [TOP [X]]; } IF(ID [X]> ID [Y])スワップ(X、Y); RES + =クエリ(ID [X]、ID [Y]、1、N-、1。); リターンのres; } int型のmain(){ scanf関数(" %のD "、&N) memsetの(頭、 - 1、はsizeof (ヘッド))。 以下のために(int型 i = 1 ; iがn <; iは++ ){ int型Uを、V。 scanf関数(" %d個の%d個"、&U&V); U ++; V ++ ; (V、U)を追加します。 } のscanf(" %dの"、&M)。 CNT = 0、TOT =0 ; DFS1(1、0)、DFS2(1、1 )。 (ビルド1、nは、1 )。 一方、(M-- ){ チャー OP [ 10 ]。 int型のL、R、RT、ヴァル。 scanf関数(" %sの" 、OP)。 もし(OP [ 0 ] == ' A ' ){ scanf関数(" %D%D%D "、&L&R&ヴァル)。 L ++; R ++ ; 更新(L、R、ヴァル)。 } 他{ scanfの(" %のD "、&RT); RT ++ ; のprintf(" %LLDの\のN- "、クエリ(ID [RT]、ID [RT] +サイズ[RT] - 。1、1、N - 、1 )); // サブツリーのサイズがサイズであるので、[RT]、出発点は、IDの数であり、[RT]をIDから[RT] IDに[RT] +サイズ[RT ] - 1 } } 戻り 0 ; }