BZOJ 1036: [ZJOI2008]树的统计Count 树链剖分

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/kidsummer/article/details/84317848

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

猜你喜欢

转载自blog.csdn.net/kidsummer/article/details/84317848