BZOJ 1036: [ZJOI2008]樹的統計Count 樹鏈剖分
阿新 • • 發佈:2018-11-27
Description
一棵樹上有n個節點,編號分別為1到n,每個節點都有一個權值w。我們將以下面的形式來要求你對這棵樹完成
一些操作: I. CHANGE u t : 把結點u的權值改為t II. QMAX u v: 詢問從點u到點v的路徑上的節點的最大權值 I
II. QSUM u v: 詢問從點u到點v的路徑上的節點的權值和 注意:從點u到點v的路徑上的節點包括u和v本身
Input
輸入的第一行為一個整數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之間。
Output
對於每個“QMAX”或者“QSUM”的操作,每行輸出一個整數表示要求輸出的結果。
Sample Input
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
Sample Output
4
1
2
2
10
6
5
6
5
16
HINT
思路:
這也是一個裸的樹鏈剖分。
剖分之後,我們就用線段樹維護就行。
一開始我的程式一直 T ,原因是我的陣列開小了。開大一點然後就過了。
線段樹維護兩個值,一個是 max, 一個是 sum
#include<bits/stdc++.h>
#define lson now << 1
#define rson now << 1 | 1
using namespace std;
const int N = 3e4+100;
struct seg
{
int Max,Sum,lazy;
}tree[N<<2];
int n,m;
int Head[ N],Next[N*2],To[N*2],cnt,w[N],wt[N];
int top[N],f[N],son[N],dep[N],id[N],size[N],tim;
int ans1,ans2;
void Add_edge(int u, int v){
To[++cnt] = v;
Next[cnt] = Head[u];
Head[u] = cnt;
}
void dfs1(int u, int fa){
dep[u]= dep[fa] + 1;
f[u] = fa; size[u] = 1;
for (int i = Head[u]; i; i = Next[i]){
int v = To[i];
if (v == fa) continue;
dfs1(v,u);
size[u] += size[v];
if (size[v] > size[son[u]]) son[u] = v;
}
}
void dfs2(int u, int topf){
id[u] = ++tim;
wt[tim] = w[u];
top[u] = topf;
if (!son[u]) return;
dfs2(son[u],topf);
for (int i = Head[u]; i; i = Next[i]){
int v = To[i];
if (v == f[u] || v == son[u]) continue;
dfs2(v,v);
}
}
void Build(int now, int l, int r){
if (l + 1 == r) {
tree[now].Sum = tree[now].Max = wt[l];
return;
}
int mid = (l + r) >> 1;
Build(lson,l, mid); Build(rson,mid, r);
tree[now].Sum = tree[lson].Sum + tree[rson].Sum;
tree[now].Max = max(tree[lson].Max,tree[rson].Max);
}
void Insert(int now, int l, int r, int a, int k){
if (l + 1 == r){
tree[now].Sum = k;
tree[now].Max = k;
return;
}
int mid = (l + r) >> 1;
if (a < mid) Insert(lson,l,mid,a,k);
if (a >= mid) Insert(rson,mid,r,a,k);
tree[now].Sum = tree[lson].Sum + tree[rson].Sum;
tree[now].Max = max(tree[lson].Max,tree[rson].Max);
}
void Query(int now, int l, int r, int a, int b){
if (a <= l && b >= r - 1){
ans1 += tree[now].Sum;
ans2 = max(ans2,tree[now].Max);
return;
}
int mid = (l + r) >> 1;
if (a < mid) Query(lson,l,mid,a,b);
if (b >= mid) Query(rson,mid,r,a,b);
}
void ask_query(int x, int y){
while(top[x] != top[y]){
if (dep[top[x]] < dep[top[y]]) swap(x,y);
Query(1,1,n+1,id[top[x]],id[x]);
x = f[top[x]];
}
if (dep[x] < dep[y]) swap(x,y);
Query(1,1,n+1,id[y],id[x]);
}
int main(){
int x,y;
char s[10];
scanf("%d",&n);
for (int i = 1; i < n; i++){
scanf("%d%d",&x,&y);
Add_edge(x,y); Add_edge(y,x);
}
for (int i = 1; i <= n; i++){
scanf("%d",&w[i]);
}
dfs1(1,0); dfs2(1,1);
Build(1,1,n+1);
scanf("%d",&m);
for (int i = 0; i < m; i++){
scanf("%s",s);
scanf("%d%d",&x,&y);
ans1 = 0;
ans2 = -1e5;
if (s[1] == 'H'){
Insert(1,1,n+1,id[x],y);
} else
if (s[1] == 'M') {
ask_query(x,y);
printf("%d\n",ans2);
} else{
ask_query(x,y);
printf("%d\n",ans1);
}
}
return 0;
}
/*
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
*/