1. 程式人生 > >BZOJ 1036: [ZJOI2008]樹的統計Count 樹鏈剖分

BZOJ 1036: [ZJOI2008]樹的統計Count 樹鏈剖分

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 */