1. 程式人生 > >[國家集訓隊]旅遊——[樹鏈剖分]

[國家集訓隊]旅遊——[樹鏈剖分]

【題目描述】 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),輸出答案。

Sample&ThickSpace;InputSample\;Input

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

Sample&ThickSpace;OutputSample\;Output

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],<