問題の意味
パスに、最小限に子供に右を指してポイントをクエリ・ツリーのルートを変更するには、再割り当て:根付いた木を考えると、3つの動作モードがあります
100データの%、N <= 100000、M < = 100000,0 <= <2に所有権の値31です。
問題の解決策
あなたはルートを変更しない場合、その後、それは分割ツリーチェーンの素朴な疑問です。
そして、操作方法のルートに変更する?LCT?
どんな効果を有することができるルートの変更を検討し、最初の変更は2点間のルートパスを変更しないであろう、本のパス上の2点が固定されています。
そのサブツリーのために?
このようなツリーは、例をとると、その現在のルートのルート= 4と仮定
次いで、これらの点のサブツリーが変更されます:独自のサブツリーは、ツリー全体、経路上の原点のツリーになる彼と第1ルートノード(1,2)、不変のまま。
どのように2番目の変更を考えてみましょう、あなたは彼の息子が、ツリー全体サブツリーマイナスの木、マイナス彼の息子のルートを含むサブツリーとなり見ることができます。
なお、この問題は解決策になることができるように、最小値を選択することは、2つのサブツリーの間隔を差し引くためのDFSに分割されているときに、それが意図され、このような性質です。
#include <ビット/ STDC ++ H> 使用して 名前空間STDを、 #defineは長い長いっ のconst int型 MAXN = 100005 ; constの LLのOO = 2100億。 INTのN、M、nowroot。 INT [MAXN]、AA [MAXN] int型CNT、ヘッド[MAXN]。 int型 DEP [MAXN]、FA [MAXN] [ 25 ]、サイズ[MAXN]、息子[MAXN]。 INT TOP [MAXN]、ID [MAXN]。 INTの根、LS [MAXN << 1 ]、RS [MAXN << 1 ]。 LL MI [MAXN << 1 ]、タグ[MAXN << 1 ]。 構造体のエッジ{ int型の次のy; } E [MAXN << 1 ]。 テンプレート < クラス T> ボイドリード(T&X){ X = 0。チャー CH = GETCHAR()。 しばらく(!isdigit(CH))CH = getchar関数(); 一方、(isdigit(CH)){X =(X << 1)+(X << 3)+(CH ^ 48)、CH = GETCHAR();} } LL分(LLのX、LLのY){ 戻り X <Y?X:Y;} ボイド追加(int型のx、int型のY){ E [ ++ CNT =(エッジ){Y、ヘッド[X]}。 ヘッド[X] = CNT。 } ボイド DFS(INT U){ サイズ[U] = 1 。 以下のために(int型 i = 1 ; iは<= 20 ; iは++)FA [U] [I] = FA [FA [U] [I- 1 ]] [I- 1 ]。 用(int型 ; I I = I =ヘッド[U] {E [I] .next) int型、V = E [I] .Y。 もし(V == FA [U] [ 0 ])続けます。 FA [V] [ 0 ] = U。 DEP [V] = DEP [U] +1 ; DFS(V); サイズ[U] + = サイズ[V]。 もし(サイズ[息子[U] <サイズ[V])息子[U] = V。 } } ボイド DFS(INT U、INT TP){ ID [U] = ++ CNT。 AA [CNTは] = [U]を。 [U]トップ = TPと、 もし(!息子[U])のリターン; DFS(息子[U]、TP)。 用(int型 ; I I = I =ヘッド[U] {E [I] .next) int型、V = E [I] .Y。 もし(V == FA [U] [ 0] || V ==息子[U])続けます。 DFS(V、V); } } ボイド更新(INT RT){ MI [RT] = 分(MI [LS [RT]、MI [RS [RT])。 } ボイドビルド(INT&RT、int型の L、INT R){ RT = ++ CNT;タグ[RT] = - 1 。 もし(L == R){MI [RT] = AA [L]。リターン;} int型ミッド=(L + R)>> 1 。 ビルド(LS [RT]、L、MID)。 ビルド(RS [RT]、ミッド + 1 、R)。 アップデート(RT)。 } のボイドput_tag(INT RT、LLヴァル){ MI [RT] =タグ[RT] = ヴァル。 } ボイド push_down(INT RT){ put_tag(LS [RT]、タグ[RT])。 put_tag(RS [RT]、タグ[RT])。 タグ[RT] = - 1 。 } ボイドは、(変更INT RT、INT L、INT R、INT a_l、INT A_R、LLヴァル){ 場合(a_l <= 1 && R <= A_R){ put_tag(RT、ヴァル)を、 返します。 } INT半ば=(L + R)>> 1 。 もし(タグ[RT] =! - 1 )push_down(RT)。 もし(a_l <= MID)変更(LS [RT]、L、中間、a_l、A_R、ヴァル)。 もし(MID <A_R)を変更(RS [RT]、ミッド+ 1 、R、a_l、A_R、ヴァル)。 アップデート(RT)。 } ボイド(変更int型のx、int型のY、LLヴァル){ 一方(上面[X]!= TOP [Y]){ 場合(DEP [TOP [X]]> DEP [トップ[Y])スワップ(Xは、 Y); (変更1、1 、nは、ID [トップ[Y]、ID [Y]、ヴァル)。 Y = FA [トップ[Y] [ 0 ]。 } もし(DEP [X]> DEP [Y])スワップ(X、Y) (変更 ANSを。 1、1 、nは、ID [x]は、ID [Y]、ヴァル)。 } LLクエリ(INT RT、INT L、INT R、INT a_l、INT A_R){ 場合(a_l <= 1 && R <= A_R)リターンMI [RT]。 もし(!タグ[RT] = - 1 )push_down(RT)。 INT 半ば=(L + R)>> 1 。 LL ANS = OO; もし(a_l <= MID)ANS = 分(ANS、クエリ(LS [RT]、L、中間、a_l、A_R))。 もし(MID <A_R)ANS =分(ANS、クエリ(RS [RT]、ミッド+ 1 、R、a_l、A_R))。 リターンのmain(){ } int型 (n)を読み出す;(m)を読み出します。 以下のために(int型 i = 1 ; iがn <; iは++ ){ int型X、Y。 読み取り(X)、(Y)を読み出します。 (x、y)を追加し、(x、y)を加えます。 } のために(int型 I = 1は iが++; iがn = < 読み出す([I]))。 (ルート)を読みます。 DEP [ルート] = 1 。 DFS(ルート)。 CNT = 0 ; DFS(根、根)。 CNT = 0 ; ビルド(LS [ 0 ]、1 、N) 以下のための(int型私は=1 ; iが<= M; iは++ ){ int型のオペアンプと、OP(読み取り) もし(OPの== 1 )を読み出す(ルート)。 そう であれば(オペアンプ== 2 ){ int型X、Y。 LLのZ。 読み取り(X)、(Y)を読み出す;(z)を読み取ります。 (x、y、z)を修正します。 } 他{ int型のX;(x)を読み出します。 もし(x ==ルート)のprintf(" %LLDする\ n "、MI [ 1 ])。 // 整颗树 他の 場合(ID [ルート]> ID [X] && ID [ルート<ID [X] +サイズ[X]){ // Xのサブツリーが変化 INT POS =ルート、DELT = DEP [POS] -dep [X] - 。1 ; のための(int型 P = 0 ; DELTと、DELT = >> 1、P ++)// 乗算 IF(&DELTを1。)POS = FA [POS] [P]; のprintf(" %LLDの\のN- "、分(クエリ(1、1、N-、1、ID [POS] - 。1)、クエリ(1、1、N - 、ID [ POS] + サイズ[POS]、N-))); } 他のprintf(" %LLDの\のN- "、クエリ(。1、1、N - 、ID [X]、ID [X] +サイズ[X] - 1)); // 全く影響 } } }