傳送門
題目描述
一棵樹上有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的路徑上的節點的權值和 注意 從點...