[国家集训队]旅游——[树链剖分]

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

S a m p l e &ThickSpace; I n p u t Sample\;Input SampleInput

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

S a m p l e &ThickSpace; O u t p u t Sample\;Output SampleOutput

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],top_heavy);
i := head[now];
while i <> 0 do
    begin
        v := edge[i].tar;
        if (v <> father[now]) and (v <> son[now])
            then DFS2 (v,v);
        i := edge[i].next;
    end;
end;

begin
readln (n);
for i := 1 to n-1 do
    begin
        readln (x,y,z);
        inc (x); inc (y);
        connect (x,y,z);
        connect (y,x,z);
    end;
DFS1 (1,0,1);
DFS2 (1,1);
build (1,1,n);
readln (q);
for i := 1 to q do
    begin
        readln (s);
        k := pos (' ',s);
        opt := copy (s,1,k-1);
        delete (s,1,k);
        k := pos (' ',s);
        val (copy (s,1,k-1),x);
        val (copy (s,k+1,length (s)-k),y);
        if opt = 'SUM'
            then begin
                     inc (x); inc (y);
                     ans := 0;
                     QRV (x,y);
                     writeln (ans);
                 end;
        if opt = 'MAX'
            then begin
                     inc (x); inc (y);
                     ans := -INF;
                     QRMax (x,y);
                     writeln (ans);
                 end;
        if opt = 'MIN'
            then begin
                     inc (x); inc (y);
                     ans := INF;
                     QRMin (x,y);
                     writeln (ans);
                 end;
        if opt = 'C'
            then begin
                     inc (x);
                     //which (x);
                     updateChange (1,1,n,id[x],id[x],y);
                 end;
        if opt = 'N'
            then begin
                     inc (x); inc (y);
                     MR (x,y);
                 end;
    end;
//return 0;
end.



  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值