HYSBZ 1036 [ZJOI2008]樹的統計Count

題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=1036


[ZJOI2008]樹的統計Count

Time Limit: 10 Sec  Memory Limit: 162 MB

Submit: 12941  Solved: 5206

[Submit][Status][Discuss]

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

Source


思路:樹鏈剖分的模板題。此題是基於點權的操作,比較容易理解,不多解釋。詳見代碼。


附上AC代碼:

#include <bits/stdc++.h>
#define lrt rt<<1
#define rrt rt<<1|1
#define lson l, m, lrt
#define rson m+1, r, rrt
using namespace std;
const int maxn = 30005;
// 分別表示以當前節點作爲根的子樹的節點數目,
// 樹上各個節點的初始值,當前節點的重兒子
int sizev[maxn], num[maxn], son[maxn];
// 分別表示樹鏈上深度最小的節點,當前節點的深度,
// 原節點在剖分後的時間戳,即新的編號
int top[maxn], deep[maxn], pos[maxn];
// 分別表示當前時間戳對應的原節點編號,
// 當前節點的父節點
int level[maxn], p[maxn];
// 判斷該節點是否被訪問過了
bool vis[maxn];
// 分別表示節點數,詢問數和時間戳計數
int n, q, cnt;
// 存儲樹的各個節點所連接的邊
vector<int> edge[maxn];

void init(){
	for (int i=1; i<=n; ++i){
		sizev[i] = top[i] = son[i] = 0;
		deep[i] = pos[i] = level[i] = 0;
		p[i]=0, vis[i]=false;
		cnt = 0;
		edge[i].clear();
	}
}

void add_edge(int u, int v){
	edge[u].push_back(v);
	edge[v].push_back(u);
}

void dfs1(int u, int root){
	vis[u] = true;
	sizev[u] = 1;
	p[u] = root;
	deep[u] = deep[root]+1;
	int siz = edge[u].size();
	for (int i=0; i<siz; ++i){
		int v = edge[u][i];
		if (v!=p[u] && !vis[v]){
			dfs1(v, u);
			sizev[u] += sizev[v];
			if (son[u] == 0)
				son[u] = v;
			else if (sizev[son[u]] < sizev[v])
				son[u] = v;
		}
	}
}

void dfs2(int u, int root){
	vis[u] = true;
	pos[u] = ++cnt;
	level[cnt] = u;
	top[u] = root;
	if (son[u])
		dfs2(son[u], root);
	int siz = edge[u].size();
	for (int i=0; i<siz; ++i){
		int v = edge[u][i];
		if (v!=p[u] && v!=son[u] && !vis[v])
			dfs2(v, v);
	}
}

int sumv[maxn<<2], maxv[maxn<<2];
int value[maxn];
char op[10];

void push_up(int rt){
	sumv[rt] = sumv[lrt]+sumv[rrt];
	maxv[rt] = max(maxv[lrt], maxv[rrt]);
}

void build(int l, int r, int rt){
	if (l == r){
		sumv[rt] = maxv[rt] = value[level[l]];
		return ;
	}
	int m = (l+r)>>1;
	build(lson);
	build(rson);
	push_up(rt);
}

void modify(int p, int val, int l, int r, int rt){
	if (l == r){
		sumv[rt] = val;
		maxv[rt] = val;
		return ;
	}
	int m = (l+r)>>1;
	if (p <= m)
		modify(p, val, lson);
	else
		modify(p, val, rson);
	push_up(rt);
}

int query(int ql, int qr, int l, int r, int rt, bool ok){
	if (ql<=l && r<=qr)
		return ok ? sumv[rt] : maxv[rt];
	int m = (l+r)>>1;
	int ans = ok ? 0 : INT_MIN;
	if (ql <= m){
		int t = query(ql, qr, lson, ok);
		ans = ok ? ans+t : max(ans, t);
	}
	if (qr > m){
		int t = query(ql, qr, rson, ok);
		ans = ok ? ans+t : max(ans, t);
	}
	return ans;
}

int seek(int x, int y, bool ok){
	int ans = ok ? 0 : INT_MIN;
	while (top[x] != top[y]){
		if (deep[top[x]] < deep[top[y]])
			swap(x, y);
		int t = query(pos[top[x]], pos[x], 1, n, 1, ok);
		ans = ok ? ans+t : max(ans, t);
		x = p[top[x]];
	}
	if (deep[x] > deep[y])
		swap(x, y);
	int t = query(pos[x], pos[y], 1, n, 1, ok);
	return ok ? ans+t : max(ans, t);
}

int main(){
	while (~scanf("%d", &n)){
		init();
		int a, b;
		for (int i=1; i<n; ++i){
			scanf("%d%d", &a, &b);
			add_edge(a, b);
		}
		for (int i=1; i<=n; ++i)
			scanf("%d", value+i);
		dfs1(1, 0);
		memset(vis, false, sizeof(bool)*(n+1));
		dfs2(1, 1);
		build(1, cnt, 1);
		scanf("%d", &q);
		while (q--){
			scanf("%s%d%d", op, &a, &b);
			if (op[1] == 'H')
				modify(pos[a], b, 1, cnt, 1);
			else if (op[1] == 'M')
				printf("%d\n", seek(a, b, false));
			else
				printf("%d\n", seek(a, b, true));
		}
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章