cogs1583 POJ3237 樹的維護

2022-04-02 07:23:04 字數 2910 閱讀 1664

★★★☆   輸入檔案:maintaintree.in輸出檔案:maintaintree.out簡單對比

時間限制:5 s   記憶體限制:128 mb

給你由n個結點組成的樹。樹的節點被編號為1到n,邊被編號為1到n-1。每一條邊有乙個權值。然後你要在樹上執行一系列指令。指令可以是如下三種之一:

change i v:將第i條邊的權值改成v。

negate a b:將點a到點b路徑上所有邊的權值變成其相反數。

query a b:找出點a到點b路徑上各邊的最大權值。

輸入檔案的第一行有乙個整數n(n<=10000)。

接下來n-1行每行有三個整數a,b,c,代表點a和點b之間有一條權值為c的邊。這些邊按照其編號從小到大給出。

接下來是若干條指令(不超過10^5條),都按照上面所說的格式。

輸入檔案的最後一行是"done".

對每個「query」指令,輸出一行,即路徑上各邊的最大權值。

1 2 1

2 3 2

query 1 2

change 1 3

query 1 2

done

這裡的輸入輸出格式和poj上原題略有不同。

poj 3237 tree

難點在於取相反數操作

記錄下最大值和最小值,有取相反數操作時,就把兩個值變成相反數,再交換兩數的值就ok,然後給這個區間打上標記(線段樹的lazy標記),以後訪問或更改值時記得下傳標記就好。

#include #include 

#include

#include

using

namespace

std;

const

int maxn = 100010

;struct

edgeedge[maxn*2

];int

head[maxn],tot;

int top[maxn];//

top[v]表示v所在的重鏈的頂端節點

int fa[maxn]; //

父親節點

int deep[maxn];//

深度 int num[maxn];//

num[v]表示以v為根的子樹的節點數

int p[maxn];//

int fp[maxn];//

和p陣列相反

int son[maxn];//

重兒子

intpos;

void

init()

void addedge(int u,int

v)void dfs1(int u,int v,intd)}

void dfs2(int u,intv)}

//線段樹

struct

nodetr[maxn*3

];void build(int i,int l,int

r)void push_up(int

i)void push_down(inti)}

void update(int i,int k,int val)

push_down(i);

int mid = (tr[i].l + tr[i].r)/2

;

if(k <= mid)update(i<<1

,k,val);

else update((i<<1)|1

,k,val);

push_up(i);}

void ne_update(int i,int l,int

r) push_down(i);

int mid=(tr[i].l+tr[i].r)>>1

;

if(r<=mid)ne_update(i<<1

,l,r);

else

if(l>mid)ne_update((i<<1)|1

,l,r);

else ne_update(i<<1,l,mid),ne_update((i<<1)|1,mid+1

,r);

tr[i].min=min(tr[i<<1].min,tr[(i<<1)|1

].min);

tr[i].max=max(tr[i<<1].max,tr[(i<<1)|1

].max);

}int query(int i,int l,int r)

int findmax(int u,int v)

tmp = max(tmp,query(1

,p[f1],p[u]));

u = fa[f1]; f1 =top[u];

}if(u == v)return

tmp;

if(deep[u] >deep[v]) swap(u,v);

return max(tmp,query(1

,p[son[u]],p[v]));

}void negate(int u,int

v)

if(u==v)return

;

if(deep[u]>deep[v])swap(u,v);

ne_update(

1,p[son[u]],p[v]);

return;}

int e[maxn][3

];int

main()

dfs1(

0,1,0

); dfs2(

1,1);

build(

1,0,pos-1

);

for(int i=0;i1;i++)

char ch[10

];

intu,v;

while(1

) }

return0;

}

POJ3237 樹的維護

給你由n個結點組成的樹。樹的節點被編號為1到n,邊被編號為1到n 1。每一條邊有乙個權值。然後你要在樹上執行一系列指令。指令可以是如下三種之一 change i v 將第i條邊的權值改成v。negate a b 將點a到點b路徑上所有邊的權值變成其相反數。query a b 找出點a到點b路徑上各邊...

poj 3237 樹鏈剖分

對樹有三種操作 q a b 詢問a b路徑的最大值 n a b 對a b路徑上的數進行取反操作 a a c a b 將第a條邊的值改為b 對於取反操作,記錄區間的最大和最小值和標記k,更新線段即可。pragma comment linker,stack 1024000000,1024000000 i...

POJ 3237(樹鏈剖分)

這道題算是樹鏈剖分的模板題吧 其實也是我過的第一道樹鏈剖分的題目 歷盡千辛萬苦,終於把兩百多行的 敲出來了,ac的一瞬間還是挺爽的。在學會了樹鏈剖分之後,這道題不算很難的了,主要是在區間取反的部分注意一下細節。樹鏈剖分 挺長的,很多地方都是容易寫錯。我也是通過討論區的acmer給出的資料找出一些錯誤...