dtoj 1228 樹的統計(樹鏈剖分模板)

2021-10-11 03:15:45 字數 3853 閱讀 2847

傳送門

題目描述

一棵樹上有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」的操作,每行輸出乙個整數表示要求輸出的結果。

樣例輸入

412

2341

4213

12qmax 3

4qmax 3

3qmax 3

2qmax 2

3qsum 3

4qsum 2

1change 1

5qmax 3

4change 3

6qmax 3

4qmax 2

4qsum 3

4

樣例輸出
412

21065

6516

題解

樹剖模板題,存個自己的,寫得不好但便於複習

**:

#include

#include

#include

#include

#include

using

namespace std;

const

int maxn=

30005

;vector <

int> rd[maxn]

;struct nodetree[maxn*4]

;char ord[10]

;int n,a,b,q,cnt,w[maxn]

,f[maxn]

,dep[maxn]

,id[maxn]

,sz[maxn]

,son[maxn]

,top[maxn]

,rk[maxn]

;//f:父節點 dep:深度 id:dfs序 sz:子樹大小(包括自己) son:重兒子 top:所在鏈頂端 rk:dfs序對應下標

void

dfs1

(int nw,

int come)

}void

dfs2

(int nw,

int t)

void

build

(int nd,

int l,

int r)

int mid=

(l+r)/2

;build

(nd*

2,l,mid)

;build

(nd*2+

1,mid+

1,r)

; tree[nd]

.mx=

max(tree[nd*2]

.mx,tree[nd*2+

1].mx)

; tree[nd]

.sum=tree[nd*2]

.sum+tree[nd*2+

1].sum;

}int

check

(int nd,

int l,

int r,

int ql,

int qr)

int mid=

(l+r)/2

,res=

-30000;if

(mid>=ql) res=

max(res,

check

(nd*

2,l,mid,ql,qr));

if(midmax(res,

check

(nd*2+

1,mid+

1,r,ql,qr));

return res;

}int

query

(int nd,

int l,

int r,

int ql,

int qr)

int mid=

(l+r)/2

,res=0;

if(mid>=ql) res+

=query

(nd*

2,l,mid,ql,qr);if

(mid=query

(nd*2+

1,mid+

1,r,ql,qr)

;//這裡思路一定要清楚,兩邊分別處理在ql和qr範圍內就好

return res;

}int

sum(

int x,

int y)

if(id[x]

>id[y]

)swap

(x,y)

;//區間左右端點

return res+

query(1

,1,n,id[x]

,id[y]);

}int

maxnn

(int x,

int y)

if(id[x]

>id[y]

)swap

(x,y)

;return

max(res,

check(1

,1,n,id[x]

,id[y]))

;}voidcg(

int nd,

int l,

int r,

int tar,

int tarz)

int mid=

(l+r)/2

;if(tar<=mid)

cg(nd*

2,l,mid,tar,tarz);if

(tar>mid)

cg(nd*2+

1,mid+

1,r,tar,tarz)

; tree[nd]

.mx=

max(tree[nd*2]

.mx,tree[nd*2+

1].mx)

; tree[nd]

.sum=tree[nd*2]

.sum+tree[nd*2+

1].sum;

}int

main()

for(

int i=

1;i<=n;i++

)dfs1(1

,0);

dfs2(1

,1);

cnt=0;

build(1

,1,n);

//按照dfs序維護的目的就是讓一條鏈上的資料佔據一段連續的區間,因此無需慮當前處理的區間是否在一條鏈上,後面可以獲知鏈的兩端

scanf

("%d"

,&q)

;for

(int i=

1;i<=q;i++

)else

if(ord[1]

=='m'

)else

if(ord[1]

=='s')}

return0;

}

樹鏈剖分 樹鏈剖分講解

好了,這樣我們就成功解決了對樹上修改查詢邊權或點的問題。下面放上 vector v maxn int size maxn dep maxn val maxn id maxn hson maxn top maxn fa maxn 定義 int edge 1,num 1 struct tree e ma...

BZOJ 1036 樹的統計 Count 樹鏈剖分

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

ZJOI2008 樹的統計(樹鏈剖分)

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