注:$ LCT $ makerootはとき$リンク$でなければなりません。
あなたは$ Y $ $ X $に接続する場合:
$ Y $アクセスとスプレイその後、$ X $に直接接続された場合にのみ、あなたは$で$ Y $は明らかに適切ではない$ $(x、y)の間で息子に左のすべてを$スプレイことがわかりますA。
コード:
#include <cstdioを> する#include <ストリング> の#include <cstdlib> の#include <CTIME> の#include <アルゴリズム> の#define N 400006 名前空間stdを使用。 名前空間IO { ボイドsetIO(文字列s) { = S +の文字列"に"。 = S +アウト文字列"アウト。"; freopenは(in.c_str()、 "R"、標準入力)。 freopenは(out.c_str()、 "W"、STDOUT)。 } }。 名前空間LCT { に#define LSON T [X] .CH [0] の#define rson T [X] .CH [1] の#define GET(X)(T [T [X] .F] .CH [1] ==バツ) の#define ISR(X)(!(T [T [X] .F] .CH [0] == X || T [T [X] .F]。 int型の合計値、息子、CH [2]、REV、F。 } T [N]。 INT STA [N]。 インラインボイド押し上げ(INT X) { T [X] .SUM = T [LSON] .SUM ^ T [rson] .SUM ^ T [X] .son。 } インラインボイドマーク(INT X) { T [X] .rev ^ = 1; スワップ(LSON、rson)。 } インラインボイドプッシュダウン(int型X) { IF(T [X] .rev) { T [X] .rev ^ = 1; (LSON)マーク(LSON)であれば、 (rson)マーク(rson)であれば、 } } インラインボイド回転(int型X) { [X] .F、折りINT古い= T = T [古い] .F、その= GET(X)。 (!ISR)(旧)tは.CH [倍]場合は[トンを[倍] .CH [1] ==古い] = X; 。T [古い] .CH [] = T [X] .CH [^ 1]、T [T [古い] .CH [れる] F =古いです。 T [X] .CH [れる^ 1] =古い、T [古い] .F = X、T [X] .F =折ります。 腕立て伏せ(旧)、腕立て伏せ(x)は、 } インラインボイドスプレイ(INT X) { int型のV = 0、U = X、FA。 (!; ISR(U); STA [++ V = U U = T [U] .F)のためのSTA [++ V] = T [U] .F。 (; V; - v)のためのプッシュダウン(STA [V])。 (;(FA = T [X] .F)= U;!U = T [U] .F回し(X))のため であれば(!T [FA] .F = U) を回転させ(GET(FA)==取得(x)は、FA:X);? } ボイドアクセス(INT X) { { 用(int型、Y = 0; X; Y = X、X = T [X] .F) スプレイ(X)。 T [X] .son ^ = T [rson] .SUM。 T [X] .son ^ = T [Y] .SUM。 rson = Y。 突き上げ(X)。 } } ボイドMove_Root(INT X) { アクセス(X)。 スプレイ(X)。 マーク(X)。 } (int型x)を検索INT { アクセス(X)を、 一方、(LSON)X = LSON。 戻り値は、x; } ボイドLink_Edge(int型のx、int型のY) { Move_Root(X)。 Move_Root(Y)。 T [Y] .F = X。 T [X] .son ^ = T [Y] .SUM。 突き上げ(X)。 } ボイドCut_Edge(int型のx、int型のY) { Move_Root(X)。 アクセス(Y)、スプレイ(Y)。 T [T [Y] .CH [0]、F = 0。 T [Y] .CH [0] = 0; 突き上げ(Y)。 } ボイド更新(int型のx、int型V) { アクセス(X)。 スプレイ(X)。 T [X] .son ^ = V。 突き上げ(X)。 } int型の照会(int型のx、int型のY) { Move_Root(X)。 アクセス(Y)。 戻りT [Y] .son。 } の#undef LSON の#undef rson }。 構造体SS { int型、X、W、Y、。 SS(INT X = 0、= 0のint Y = 0 W INT):X(X)、Y(Y)、(w)はwの{} } S [N]。 int型のn; メイン()がINT { srand関数(20011011)を、 // IO :: setIO( "入力"); INT I、J、M、TOT = 0、SU = 0。 scanf関数( "%D%D%D"、&I、&N、&M)。 ため(I 1 =、iは<N; ++ I) { int型のX、Y。 scanf関数( "%D%D"、およびX&Y)。 LCT :: Link_Edge(X、Y) } のためには、(i 1 =; I <= M; ++ I) { int型OP。 scanf関数( "%のD"、&OP)。 INT X、Y、U、V。 scanf関数( "%D%D%D%D"、およびX&Y、&U、およびV)。 LCT :: Cut_Edge(X、Y) LCT :: Link_Edge(U、V); } IF(OP == 2) { int型、X、Y、W。 scanf関数( "%D%D"、およびX&Y)。 W =ランド()。 S [++ TOT = SS(X、Y、W)。 LCT ::更新(X、W)。 LCT ::更新(Y、W)。 SU ^ = W。 } IF(OP == 3) { int型のX。 scanf関数( "%のD"、&x)は、 LCT ::更新(S [X] .X、S [X] .W)。 LCT ::更新(S [X]・Y、S [X] .W)。 SU ^ = S [X] .W。 IF(OP == 4) { int型のX、Y。 scanf関数( "%D%D"、およびX&Y)。 printf( "%sの\ n"は、LCT ::クエリ(x、y)は== SU "YES": "NO")。 } } 0を返します。 }