[國家集訓隊]旅遊——[樹鏈剖分]
【題目描述】 Ray 樂忠於旅遊,這次他來到了T 城。T 城是一個水上城市,一共有 N 個景點,有些景點之間會用一座橋連線。為了方便遊客到達每個景點但又為了節約成本,T 城的任意兩個景點之間有且只有一條路徑。換句話說, T 城中只有N − 1 座橋。
Ray 發現,有些橋上可以看到美麗的景色,讓人心情愉悅,但有些橋狹窄泥濘,令人煩躁。於是,他給每座橋定義一個愉悅度w,也就是說,Ray 經過這座橋會增加w 的愉悅度,這或許是正的也可能是負的。有時,Ray 看待同一座橋的心情也會發生改變。
現在,Ray 想讓你幫他計算從u 景點到v 景點能獲得的總愉悅度。有時,他還想知道某段路上最美麗的橋所提供的最大愉悅度,或是某段路上最糟糕的一座橋提供的最低愉悅度。
【輸入格式】 輸入的第一行包含一個整數N,表示T 城中的景點個數。景點編號為 0…N − 1。
接下來N − 1 行,每行三個整數u、v 和w,表示有一條u 到v,使 Ray 愉悅度增加w 的橋。橋的編號為1…N − 1。|w| <= 1000。 輸入的第N + 1 行包含一個整數M,表示Ray 的運算元目。
接下來有M 行,每行描述了一個操作,操作有如下五種形式:
-
C i w,表示Ray 對於經過第i 座橋的愉悅度變成了w。
-
N u v,表示Ray 對於經過景點u 到v 的路徑上的每一座橋的愉悅度都變成原來的相反數。
-
SUM u v,表示詢問從景點u 到v 所獲得的總愉悅度。
-
MAX u v,表示詢問從景點u 到v 的路徑上的所有橋中某一座橋所提供的最大愉悅度。
-
MIN u v,表示詢問從景點u 到v 的路徑上的所有橋中某一座橋所提供的最小愉悅度。
測試資料保證,任意時刻,Ray 對於經過每一座橋的愉悅度的絕對值小於等於1000。
【輸出格式】 對於每一個詢問(操作S、MAX 和MIN),輸出答案。
3 0 1 1 1 2 2 8 SUM 0 2 MAX 0 2 N 0 1 SUM 0 2 MIN 0 2 C 1 3 SUM 0 2 MAX 0 2
3 2 1 -1 5 3
【題意分析】 碼量真的很讓人絕望。。。因為用pascal寫的,我的碼風寫了380行左右。。。真tm毒瘤,加上debug的時間,如果現場我還不一定做得出來。。。
//380行,快跟RBT差不多了,這道題是真的zz
很神奇的一個地方:這次單點修改時沒有去尋找資料存在了那個地方(參見我寫的月下毛景樹),直接上id[]
,就AC了,要是x經過which ()
之後(找深度更大的點)就過不了,這個問題值得研究。。。
之前的which ()
程式碼:
inline void which (int &x){
x <<= 1;
(depth[edge[x].from] < depth[edge[x].to])
? x = edge[x].to : x = edge[x].from;
}
對於這道題,維護三棵線段樹:treeV[],treeMax,treeMin[]
,分別記錄區間和,最大值,最小值。
pushdown也值得一提,因為是取反,那麼很容易想到原來最大的取反之後變成最小的了,最小的取反之後變成最大的了,區間和的話直接取反。
序號從0開始,那麼節點編號就直接+1,看著舒服。
Code:
type Front_Link_Star = record
from,tar,w,next : longint;
end;
const INF = 1 << 30;
MAXN = 300000;
var edge : array [-10..MAXN*2] of Front_Link_Star;
head : array [-10..MAXN*2] of longint;
lazy,treeV,treeMax,treeMin : array [-10..MAXN*4] of longint;
son,top,father,depth,id,rk,value,size : array [-10..MAXN] of longint;
dfn,cnt,n,q,i,x,y,z,k,ans,res : longint; s,opt : string;
Function max (x,y : longint) : longint;
begin
if x > y
then exit (x)
else exit (y);
end;
Function Min (x,y : longint) : longint;
begin
if x > y
then exit (y)
else exit (x);
end;
Procedure connect (x,y,z : longint);
begin
inc (cnt);
edge[cnt].from := x;
edge[cnt].tar := y;
edge[cnt].w := z;
edge[cnt].next := head[x];
head[x] := cnt;
end;
Procedure swap (var x,y : longint);
var temp : longint;
begin
temp := x; x := y; y := temp;
end;
//這去掉之後就AC了,不然樣例都過不了
//Procedure which (var x : longint);
//begin
//x := x << 1;
//if (depth[edge[x].from] < depth[edge[x].tar])
// then x := edge[x].tar
// else x := edge[x].from;
//end;
//上傳
Procedure pushup (now : longint);
begin
treeV[now] := treeV[now << 1] + treeV[now << 1 or 1];
treeMax[now] := max (treeMax[now << 1],treeMax[now << 1 or 1]);
treeMin[now] := min (treeMin[now << 1],treeMin[now << 1 or 1]);
end;
//pushdown是重點
Procedure pushdown (now : longint);
var lson,rson : longint;
begin
if lazy[now] <> 0
then begin
lson := now << 1; rson := now << 1 or 1;
swap (treeMin[lson],treeMax[lson]);
treeMin[lson] := -treeMin[lson];
treeMax[lson] := -treeMax[lson];
treeV[lson] := -treeV[lson];
lazy[lson] := lazy[lson] xor 1;
swap (treeMin[rson],treeMax[rson]);
treeMin[rson] := -treeMin[rson];
treeMax[rson] := -treeMax[rson];
treeV[rson] := -treeV[rson];
lazy[rson] := lazy[rson] xor 1;
lazy[now] := 0;
end;
end;
Procedure build (now,tl,tr : longint);
var mid : longint;
begin
lazy[now] := 0;
if tl = tr
then begin
treeV[now] := value[rk[tl]];
treeMax[now] := value[rk[tl]];
treeMin[now] := value[rk[tl]];
exit;
end;
mid := (tl + tr) >> 1;
build (now << 1,tl,mid);
build (now << 1 or 1,mid+1,tr);
pushup (now);
end;
//單點修改
Procedure updateChange (now,tl,tr,left,right,change : longint);
var mid : longint;
begin
if (right < tl) or (tr < left)
then exit;
if (left <= tl) and (tr <= right)
then begin
treeV[now] := change;
treeMax[now] := change;
treeMin[now] := change;
exit;
end;
pushdown (now);
mid := (tl + tr) >> 1;
updateChange (now << 1,tl,mid,left,right,change);
updateChange (now << 1 or 1,mid+1,tr,left,right,change);
pushup (now);
end;
//取反
Procedure updateReverse (now,tl,tr,left,right : longint);
var mid : longint;
begin
if (right < tl) or (tr < left)
then exit;
if (left <= tl) and (tr <= right)
then begin
swap (treeMin[now],treeMax[now]);
treeMin[now] := -treeMin[now];
treeMax[now] := -treeMax[now];
treeV[now] := -treeV[now];
lazy[now] := lazy[now] xor 1;
exit;
end;
pushdown (now);
mid := (tl + tr) >> 1;
updateReverse (now << 1,tl,mid,left,right);
updateReverse (now << 1 or 1,mid+1,tr,left,right);
pushup (now);
end;
Procedure queryV (now,tl,tr,left,right : longint);
var mid : longint;
begin
if (right < tl) or (tr < left)
then exit;
if (left <= tl) and (tr <= right)
then begin
inc (res,treeV[now]);
exit;
end;
pushdown (now);
mid := (tl + tr) >> 1;
queryV (now << 1,tl,mid,left,right);
queryV (now << 1 or 1,mid+1,tr,left,right);
pushup (now);
end;
Procedure queryMax (now,tl,tr,left,right : longint);
var mid : longint;
begin
if (right < tl) or (tr < left)
then exit;
if (left <= tl) and (tr <= right)
then begin
res := max (res,treeMax[now]);
exit;
end;
pushdown (now);
mid := (tl + tr) >> 1;
queryMax (now << 1,tl,mid,left,right);
queryMax (now << 1 or 1,mid+1,tr,left,right);
pushup (now);
end;
Procedure queryMin (now,tl,tr,left,right : longint);
var mid : longint;
begin
if (right < tl) or (tr < left)
then exit;
if (left <= tl) and (tr <= right)
then begin
res := min (res,treeMin[now]);
exit;
end;
pushdown (now);
mid := (tl + tr) >> 1;
queryMin (now << 1,tl,mid,left,right);
queryMin (now << 1 or 1,mid+1,tr,left,right);
pushup (now);
end;
//Modify_Range
Procedure MR (x,y : longint);
begin
while top[x] <> top[y] do
begin
if (depth[top[x]] < depth[top[y]])
then swap (x,y);
updateReverse (1,1,n,id[top[x]],id[x]);
x := father[top[x]];
end;
if x = y
then exit;
if depth[x] > depth[y]
then swap (x,y);
updateReverse (1,1,n,id[x]+1,id[y]);
end;
//Query_Range_Value
Procedure QRV (x,y : longint);
begin
while top[x] <> top[y] do
begin
if (depth[top[x]] < depth[top[y]])
then swap (x,y);
res := 0;
queryV (1,1,n,id[top[x]],id[x]);
inc (ans,res);
x := father[top[x]];
end;
if x = y
then exit;
if depth[x] > depth[y]
then swap (x,y);
res := 0;
queryV (1,1,n,id[x]+1,id[y]);
inc (ans,res);
end;
//Query_Range_Min
Procedure QRMin (x,y : longint);
begin
while top[x] <> top[y] do
begin
if (depth[top[x]] < depth[top[y]])
then swap (x,y);
res := INF;
queryMin (1,1,n,id[top[x]],id[x]);
ans := min (ans,res);
x := father[top[x]];
end;
if x = y
then exit;
if depth[x] > depth[y]
then swap (x,y);
res := INF;
queryMin (1,1,n,id[x]+1,id[y]);
ans := min (ans,res);
end;
//Query_Range_Max
Procedure QRMax (x,y : longint);
begin
while top[x] <> top[y] do
begin
if (depth[top[x]] < depth[top[y]])
then swap (x,y);
res := -INF;
queryMax (1,1,n,id[top[x]],id[x]);
ans := max (ans,res);
x := father[top[x]];
end;
if x = y
then exit;
if depth[x] > depth[y]
then swap (x,y);
res := -INF;
queryMax (1,1,n,id[x]+1,id[y]);
ans := max (ans,res);
end;
Procedure DFS1 (now,fa,d : longint);
var maxson,v,i : longint;
begin
father[now] := fa;
depth[now] := d;
size[now] := 1;
maxson := -1;
i := head[now];
while i <> 0 do
begin
v := edge[i].tar;
if v = fa
then begin
i := edge[i].next;
continue;
end;
DFS1 (v,now,d+1);
value[v] := edge[i].w;
inc (size[now],size[v]);
if size[v] > maxson
then begin
son[now] := v;
maxson := size[v];
end;
i := edge[i].next;
end;
end;
Procedure DFS2 (now,top_heavy : longint);
var v,i : longint;
begin
top[now] := top_heavy;
inc (dfn);
id[now] := dfn;
rk[dfn] := now;
if (son[now] = 0)
then exit;
DFS2 (son[now],<