传送门:洛谷2590
题目描述
一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。
我们将以下面的形式来要求你对这棵树完成一些操作:
I. CHANGE u t : 把结点u的权值改为t
II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值
III. QSUM u v: 询问从点u到点v的路径上的节点的权值和
注意:从点u到点v的路径上的节点包括u和v本身
分析
裸的树链剖分,对于单点修改+区间求和+区间最值,直接用线段树维护就好了.
树状数组写挂了,尴尬
代码
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define IL inline
using namespace std;
IL int read()
{
char c = getchar();
int sum = 0 ,k = 1;
for(;'0' > c || c > '9'; c = getchar())
if(c == '-') k = -1;
for(;'0' <= c && c <= '9'; c = getchar()) sum = sum * 10 + c - '0';
return sum * k;
}
const int maxn = 3e4 + 5, inf = 0x3f3f3f3f;
int n;
int num[maxn];
int to[maxn << 1], nxt[maxn << 1];
int cnt;
int last[maxn];
IL void add(int u, int v)
{
++cnt; to[cnt] = v; nxt[cnt] = last[u]; last[u] = cnt;
++cnt; to[cnt] = u; nxt[cnt] = last[v]; last[v] = cnt;
}
int fa[maxn], dep[maxn], size[maxn], son[maxn];
int dfn, top[maxn], seg[maxn];
struct node
{
node *lch, *rch;
int sum, ma;
IL node()
{
lch = rch = 0; sum = 0;
ma = -inf;
}
}* root;
IL int max_(int x, int y) { return x > y ? x : y; }
IL void swap_(int &x, int &y) { int tmp = x; x = y; y = tmp;}
IL void dfs1(int u)
{
size[u] = 1;
for(int i = last[u], v; v = to[i]; i = nxt[i])
if(v != fa[u])
{
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
if(size[v] > size[son[u]]) son[u] = v;
size[u] += size[v];
}
}
IL void dfs2(int u, int topf)
{
top[u] = topf;
seg[u] = ++dfn;
if(!son[u]) return ;
dfs2(son[u], topf);
for(int i = last[u], v; v = to[i]; i = nxt[i])
if(v != fa[u] && v != son[u])
dfs2(v, v);
}
IL void pushup(node *p)
{
p->sum = p->lch->sum + p->rch->sum;
p->ma = max_(p->lch->ma, p->rch->ma);
}
IL void build(node *p, int l, int r)
{
if(l == r) { p->sum = p->ma = num[l]; return ;}
int mid = (l + r) >> 1;
p->lch = new node; build(p->lch, l, mid);
p->rch = new node; build(p->rch, mid + 1, r);
pushup(p);
}
IL void update(node *p, int l, int r, int k)
{
if(l == r) { p->sum = p->ma = num[l]; return ;}
int mid = (l + r) >> 1;
if(k <= mid) update(p->lch, l, mid, k); else update(p->rch, mid + 1, r, k);
pushup(p);
}
IL int querysum(node *p, int l, int r, int x, int y)
{
if(l == x && r == y) return p->sum;
int mid = (l + r) >> 1;
if(y <= mid) return querysum(p->lch, l, mid, x, y);
if(mid < x) return querysum(p->rch, mid + 1, r, x, y);
return querysum(p->lch, l, mid, x, mid) + querysum(p->rch, mid + 1, r, mid + 1, y);
}
IL int querymax(node *p, int l, int r, int x, int y)
{
if(l == x && r == y) return p->ma;
int mid = (l + r) >> 1;
if(y <= mid) return querymax(p->lch, l, mid, x, y);
if(mid < x) return querymax(p->rch, mid + 1, r, x, y);
return max_(querymax(p->lch, l, mid, x, mid), querymax(p->rch, mid + 1, r, mid + 1, y));
}
IL int solve(int x, int y, bool k)
{
int ans = k ? 0 : -inf;
for(;top[x] != top[y];)
{
if(dep[top[x]] < dep[top[y]]) swap_(x, y);
if(k) ans += querysum(root, 1, n, seg[top[x]], seg[x]); else ans = max_(ans, querymax(root, 1, n, seg[top[x]], seg[x]));
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap_(x, y);
if(k) ans += querysum(root, 1, n, seg[x], seg[y]); else ans = max_(ans, querymax(root, 1, n, seg[x], seg[y]));
return ans;
}
int main()
{
n = read();
for(int i = 1; i < n; ++i)
add(read(), read());
dfs1(1);
dfs2(1, 1);
for(int i = 1; i <= n; ++i) num[seg[i]] = read();
root = new node;
build(root, 1, n);
char c[10];
for(int m = read(), x, y; m; --m)
{
scanf(" %s", c); x = read(); y = read();
if(c[0] == 'C')
{
num[seg[x]] = y;
update(root, 1, n, seg[x]);
}else
if(c[0] == 'Q')
printf("%d\n", solve(x, y, c[1] == 'S'));
}
return 0;
}