1036 ZJOI2008 樹的統計Count

2022-05-12 10:09:41 字數 3399 閱讀 7507

一棵樹上有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」的形式給出。 對於100%的資料,保證1<=n<=30000,0<=q<=200000;中途操作中保證每個節點的權值w在-30000到30000之間。

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

41 2

2 34 1

4 2 1 3

12qmax 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 441

22106

56516

裸樹鏈剖分。。。寫的時候要注意點權有負的情況,邊是兩倍,因為是雙向邊。。。

對於樹鏈剖分實際上就是乙個把一棵樹變成很多條鏈,這樣子在樹上的操作就變成了區間操作,這樣再依託於資料結構就好了。。。

不過對於一棵樹,如何劃分也是有標準的。。。對於一顆樹我們設第i個點的兒子節點數為son[i],那麼對於乙個節點在它的所有兒子x中son[x]最大的稱為重點。。。如果一條鏈上的所有點都是重點,那麼這條鏈就是重鏈。。。這樣一來一棵樹就變成了一條一條的鏈,這樣就可以變為區間操作了。。。

我們可以通過兩次dfs來找到重鏈。。。第一次dfs可以求出乙個節點的子節點個數,它的父節點。。。

void dfs(int x)

}}void dfs2(int x,int chain)

然後第二次dfs來求出重鏈,然後用dfs的順序對每個點重新編號,然後建立資料結構即可。。。

4 #include5 #include6 #include7 #include8 #include9 #include10 #include

11 #include12 #include13 #include14 #include

15#define inf 1000000000

16#define maxn 30005

17#define maxm 30005*2

18#define eps 1e-10

19#define ll long long

20#define for0(i,n) for(int i=0;i<=(n);i++)

21#define for1(i,n) for(int i=1;i<=(n);i++)

22#define for2(i,x,y) for(int i=(x);i<=(y);i++)

23#define for3(i,x,y) for(int i=(x);i>=(y);i--)

24#define for4(i,x) for(int i=head[x],y=e[i].go;i;i=e[i].next,y=e[i].go)

25using

namespace

std;

26int

read()

2730

while(ch>='

0'&&ch<='9')

31return x*f;32}

33struct

treef[maxn*4

];36

struct

edgee[maxm];

39int

head[maxn],w[maxn],top[maxn],fa[maxn],p[maxn],son[maxn],s[maxn],dep[maxn],a[maxn],tot,cnt;

40void pushup(int

i)44

45void build(int i,int left,int

right)

53 build(i*2

,left,mid);

54 build(i*2+1,mid+1

,right);

55pushup(i);56}

5758

void change(int i,int goal,int

v)64

if(mid>=goal)change(i*2

,goal,v);

65else change(i*2+1

,goal,v);

66pushup(i);67}

6869

int query(int i,int left,int

right)

7677

int qmax(int i,int left,int

right)

84void insert(int u,int

v)87

void ins(int u,int

v)90

void dfs(int

x)97}98

}99void dfs2(int x,int

chain)

105int solvesum(int x,int

y)112

if(dep[x]>dep[y])swap(x,y);

113 ans+=query(1

,p[x],p[y]);

114return

ans;

115}

116int solvemax(int x,int

y)123

if(dep[x]>dep[y])swap(x,y);

124 ans=max(ans,qmax(1

,p[x],p[y]));

125return

ans;

126}

127128

intmain()

136 for1(i,n)w[i]=read();

137 dfs(1);dfs2(1,1

);138 build(1,1

,n);

139 n=read();

140for1(i,n)

149else

153}

154else

158}

159return0;

160 }

view code

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的路徑上的節點的權值和 注意 從點...