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
1
2
2
10
6
5
6
5
16
solution:
树链剖分点权模板题。
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define inf -1e9
#define ls (t<<1)
#define rs (t<<1)|1
const int maxn = 30010;
int n,no, dfsxu, val[maxn],pos[maxn],head[maxn],heavy[maxn],top[maxn],idx[maxn],dep[maxn],fa[maxn],size[maxn];
struct Edge
{
int to, next;
}edge[maxn<<1];
struct segtree
{
int l, r, sum,max;
}tree[maxn<<2];
void init()
{
no = dfsxu = 0;
memset(head, -1, sizeof(head));
memset(heavy, 0, sizeof(heavy));
dep[1] = fa[1] =size[0]=0;
}
void add(int u, int v)
{
edge[no].to = v;edge[no].next = head[u];head[u] = no++;
edge[no].to = u;edge[no].next = head[v];head[v] = no++;
}
void dfs(int x)
{
size[x] = 1;
for (int i = head[x]; ~i; i = edge[i].next)
{
int u = edge[i].to;
if (u != fa[x])
{
fa[u] = x;
dep[u] = dep[x] + 1;
dfs(u);
size[x] += size[u];
if (size[heavy[x]] < size[u])heavy[x] = u;
}
}
}
void spilt(int x, int y)//剖分
{
top[x] = y;
idx[x] = ++dfsxu;
pos[dfsxu] = x;
if (heavy[x])spilt(heavy[x], top[x]);
for (int i = head[x]; ~i; i = edge[i].next)
{
int u = edge[i].to;
if (u != fa[x] && u != heavy[x])spilt(u, u);
}
}
void pushup(int t)
{
tree[t].max = max(tree[ls].max, tree[rs].max);
tree[t].sum = tree[ls].sum + tree[rs].sum;
}
void build(int l, int r, int t)
{
tree[t].l = l; tree[t].r = r; tree[t].max = inf; tree[t].sum=0;
if (l == r){
tree[t].max = tree[t].sum = val[pos[l]];
return;
}
int mid = (l + r) >> 1;
build(l, mid,ls);
build(mid+1, r, rs);
pushup(t);
}
void update(int x, int val, int t)
{
if (tree[t].l == x&&tree[t].r == x)
{
tree[t].max = tree[t].sum = val;
return;
}
if (x <= tree[ls].r)update(x, val, ls);
else update(x, val, rs);
pushup(t);
}
int qqsum(int l, int r, int t)
{
if (tree[t].l == l&&tree[t].r == r)return tree[t].sum;
if (r <= tree[ls].r)return qqsum(l, r, ls);
else if (l >= tree[rs].l)return qqsum(l, r, rs);
return qqsum(l, tree[ls].r, ls)+qqsum(tree[rs].l, r, rs);
}
int qsum(int x, int y)
{
int ans = 0,u = top[x], v = top[y];
while (u != v)
{
if (dep[u] < dep[v]){
swap(u, v);swap(x, y);
}
ans += qqsum(idx[u], idx[x], 1);
x = fa[u];
u = top[x];
}
if (dep[x] > dep[y])swap(x, y);
ans += qqsum(idx[x], idx[y], 1);
return ans;
}
int qqmax(int l, int r, int t)
{
if (tree[t].l == l&& tree[t].r == r)return tree[t].max;
if (r <= tree[ls].r)return qqmax(l, r, ls);
else if (l >= tree[rs].l)return qqmax(l, r, rs);
return max(qqmax(l, tree[ls].r, ls), qqmax(tree[rs].l, r, rs));
}
int qmax(int x, int y)
{
int ans = inf, u = top[x], v = top[y];
while (u != v)
{
if (dep[u] < dep[v]){
swap(u, v);
swap(x, y);
}
ans = max(ans,qqmax(idx[u], idx[x], 1));
x = fa[u];
u = top[x];
}
if (dep[x] > dep[y])swap(x, y);
ans = max(ans,qqmax(idx[x], idx[y], 1));
return ans;
}
int main()
{
int x,y,q;
char op[10];
scanf("%d", &n);
init();
for (int i = 1; i < n; i++)
{
scanf("%d%d", &x, &y);
add(x, y);
}
for (int i = 1; i <= n; i++)
scanf("%d", &val[i]);
dfs(1);
spilt(1, 1);
build(1, n, 1);
scanf("%d", &q);
while (q--)
{
scanf("%s%d%d", op,&x,&y);
if (op[0] == 'C')update(idx[x], y, 1);
else if (op[1] == 'S')printf("%d\n", qsum(x,y));
else printf("%d\n", qmax(x, y));
}
return 0;
}