樹的統計 ZJOI2008

2021-09-30 13:48:03 字數 2794 閱讀 5936

描述:

一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。

我們將以下面的形式來要求你對這棵樹完成一些操作:

i. change u t : 把結點u的權值改為t

ii. qmax u v: 詢問從點u到點v的路徑上的節點的最大權值

iii. qsum u v: 詢問從點u到點v的路徑上的節點的權值和

注意:從點u到點v的路徑上的節點包括u和v本身

輸入:輸入檔案的第一行為乙個整數n,表示節點的個數。

接下來n – 1行,每行2個整數a和b,表示節點a和節點b之間有一條邊相連。

接下來一行n個整數,第i個整數wi表示節點i的權值。

接下來1行,為乙個整數q,表示操作的總數。

接下來q行,每行乙個操作,以「change u t」或者「qmax u v」或者「qsum u v」的形式給出。

輸出:

對於每個「qmax」或者「qsum」的操作,每行輸出乙個整數表示要求輸出的結果。

樣例輸入:

4 1 2

2 3

4 1

4 2 1 3

12 qmax 3 4

qmax 3 3

qmax 3 2

qmax 2 3

qsum 3 4

qsum 2 1

change 1 5

qmax 3 4

change 3 6

qmax 3 4

qmax 2 4

qsum 3 4

樣例輸出:

4 1

2 2

10 6

5 6

5 16

資料範圍:

對於100%的資料,保證1<=n<=30000,0<=q<=200000;中途操作中保證每個節點的權值w在-30000到30000之間。

解題思路:

我也是夠了,一道樹鏈剖分的模板題用了我整整乙個晚上,智商不夠啊!而且還是被乙個sb錯誤卡了下去。。。言歸正傳,正宗的樹鏈剖分模板題,線段樹上維護即可,判斷輕重子節點拉成一條鏈,用num陣列很巧妙地在樹鏈和線段樹之間轉換,非常玄學的操作,廢話不多說,上**。

#include

#include

#include

#include

using

namespace

std;

#define inf 0x3f3f3f3f

#define ld (o<<1)

#define rd ((o<<1)|1)

#define mem(a) memset(a,0,sizeof(a))

#define n 30010

struct treet[4*n];//線段樹

struct edgee[n];//邊

struct node

}p[n];//點

/*dep深度

size節點數

fa父親

w節點權值

hson重孩子

top表示每條鏈第乙個位置

*/int first[n],pred[n];

/*first 鄰接表頭指標

pred線段樹的編號是原來什麼編號

*/int n,m,last,tot;//tot記錄線段樹總編號

char c[10];

void init()

void add(int u,int v)

void dfs1(int s)

}void dfs2(int s,int tp)

}void pushup(int o)

void build(int o,int l,int r)

int mid=(l+r)>>1;

build(ld,l,mid);

build(rd,mid+1,r);

pushup(o);

}void update(int o,int p,int val)

int mid=(t[o].l+t[o].r)>>1;

if(p<=mid)update(ld,p,val);

if(p>=mid+1)update(rd,p,val);

pushup(o);

}int query_sum(int o,int l,int r)

int query_maxv(int o,int l,int r)

//求鏈 目的是想辦法跳到一條重鏈上來

//由於一顆樹只有乙個完整重蓮,如果2個點在一顆子樹上,那麼先統計輕邊,自然會轉到重邊上來。

int get_sum(int x,int y)

if(p[x].num>p[y].num)swap(x,y);

ans+=query_sum(1,p[x].num,p[y].num);

return ans;

}int get_maxv(int x,int y)

if(p[x].num>p[y].num)swap(x,y);

ans=max(ans,query_maxv(1,p[x].num,p[y].num));

return ans;

}int main()

for(int i=1;i<=n;i++)scanf("%d",&p[i].w);

dfs1(1);

dfs2(1,1);

build(1,1,tot);//構建線段樹

scanf("%d",&m);

for(int i=1;i<=m;i++)

else

}return

0;}

ZJOI 2008 樹的統計

一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作 i.change u t 把結點u的權值改為t ii.qmax u v 詢問從點u到點v的路徑上的節點的最大權值 iii.qsum u v 詢問從點u到點v的路徑上的節點的權值和 注意 從點...

ZJOI2008 樹的統計

zjoi2008 樹的統計 題目描述 一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作 i.change u t 把結點u的權值改為t ii.qmax u v 詢問從點u到點v的路徑上的節點的最大權值 iii.qsum u v 詢問從點u到...

ZJOI2008 樹的統計

一棵樹上有n個節點,編號分別為1到n,每個節點都有乙個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作 i.change u t 把結點u的權值改為t ii.qmax u v 詢問從點u到點v的路徑上的節點的最大權值 iii.qsum u v 詢問從點u到點v的路徑上的節點的權值和 注意 從點...