1036: [ZJOI2008]树的统计Count
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 19039 Solved: 7761
[ 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
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
1
2
2
10
6
5
6
5
16
树链剖分裸题
#include <bits/stdc++.h>
using namespace std;
const int N = 3e4 +10;
int n, m, tot, tot1;
int num[N], tree[N], pre[N], head[N], son[N], fa[N], data[N], top[N], deep[N];
struct xx{
int l, r, sum, maxi;
} T[N<<2];
struct xxx{
int to, nex;
} a[N<<1];
void Add(int u, int v){
a[++tot].to = v, a[tot].nex = head[u], head[u] = tot;
}
void dfs1(int k, int f, int d){
deep[k] = d, fa[k] = f, num[k] = 1;
for(int i = head[k]; i != -1; i = a[i].nex){
int to = a[i].to;
if(to == f) continue;
dfs1(to, k, d+1);
num[k] += num[to];
if(!son[k] || num[to] > num[son[k]]) son[k] = to;
}
}
void dfs2(int k, int Number){
top[k] = Number, tree[k] = ++tot1;
pre[tree[k]] = k;
if(!son[k]) return;
dfs2(son[k], Number);
for(int i = head[k]; i != -1; i = a[i].nex){
int to = a[i].to;
if(to != son[k] && to != fa[k]) dfs2(to, to);
}
}
void Build(int l, int r, int k){
T[k].l = l, T[k].r = r;
if(l == r){
T[k].sum = T[k].maxi = data[pre[l]];
return;
}
int mid = (l+r)>>1;
Build(l, mid, k<<1);
Build(mid+1, r, k<<1|1);
T[k].maxi = max(T[k<<1].maxi, T[k<<1|1].maxi);
T[k].sum = T[k<<1].sum+T[k<<1|1].sum;
}
void Update(int x, int v, int k){
if(T[k].l == T[k].r && T[k].l == x){
T[k].sum = T[k].maxi = v;
return;
}
int mid = (T[k].l+T[k].r)>>1;
if(x <= mid) Update(x, v, k<<1);
else Update(x, v, k<<1|1);
T[k].maxi = max(T[k<<1].maxi, T[k<<1|1].maxi);
T[k].sum = T[k<<1].sum+T[k<<1|1].sum;
}
int Max;
void Query_max(int l, int r, int k){
if(l <= T[k].l && r >= T[k].r){
Max = max(Max, T[k].maxi);
return;
}
if(T[k].l == T[k].r) return;
int mid = (T[k].l+T[k].r)>>1;
if(r <= mid) Query_max(l, r, k<<1);
else if(l > mid) Query_max(l, r, k<<1|1);
else{
Query_max(l, mid, k<<1);
Query_max(mid+1, r, k<<1|1);
}
}
int Sum;
void Query_sum(int l, int r, int k){
if(l <= T[k].l && r >= T[k].r){
Sum += T[k].sum;
return;
}
if(T[k].l == T[k].r) return;
int mid = (T[k].l+T[k].r)>>1;
if(r <= mid) Query_sum(l, r, k<<1);
else if(l > mid) Query_sum(l, r, k<<1|1);
else{
Query_sum(l, mid, k<<1);
Query_sum(mid+1, r, k<<1|1);
}
}
int Get_max(int x, int y){
int f1 = top[x], f2 = top[y];
Max = -0x3f3f3f3f;
while(f1 != f2){
if(deep[f1] < deep[f2]){
swap(f1, f2);
swap(x, y);
}
Query_max(tree[f1], tree[x], 1);
x = fa[f1], f1 = top[x];
}
deep[x] > deep[y] ? Query_max(tree[y], tree[x], 1) : Query_max(tree[x], tree[y], 1);
return Max;
}
int Get_sum(int x, int y){
int f1 = top[x], f2 = top[y];
Sum = 0;
while(f1 != f2){
if(deep[f1] < deep[f2]){
swap(f1, f2);
swap(x, y);
}
Query_sum(tree[f1], tree[x], 1);
x = fa[f1], f1 = top[x];
}
deep[x] > deep[y] ? Query_sum(tree[y], tree[x], 1) : Query_sum(tree[x], tree[y], 1);
return Sum;
}
int main(){
while(scanf("%d", &n) == 1){
tot = tot1 = 0;
int u, v;
memset(head, -1, sizeof head);
for(int i = 1; i < n; i++){
scanf("%d%d", &u, &v);
Add(u, v); Add(v, u);
}
for(int i = 1; i <= n; i++){
scanf("%d", &data[i]);
}
dfs1(1, 0, 1); dfs2(1, 1);
Build(1, n, 1);
scanf("%d", &m);
char op[10];
while(m--){
scanf("%s%d%d", op, &u, &v);
if(op[1] == 'H') Update(tree[u], v, 1);
else if(op[1] == 'M') printf("%d\n", Get_max(u, v));
else printf("%d\n", Get_sum(u, v));
}
}
}