Description
给你一棵树,每个点有一个权值s[i],一个颜色c[i],有四种操作:
CC x c:点x的颜色改成c;
CW x w:点x的权值调整为w;
QS x y:一位旅行者从城市x出发,到城市y,并记下了途中颜色相同的点的权值总和;
QM x y:一位旅行者从城市x出发,到城市y,并记下了途中颜色相同的点的权值最大值。
Sample Input
5 6
3 1
2 3
1 2
3 3
5 1
1 2
1 3
3 4
3 5
QS 1 5
CC 3 1
QS 1 5
CW 3 3
QS 1 5
QM 2 4
Sample Output
8
9
11
3
这题其实有一点水。。。
你将每个颜色建一个线段树,然后动态开点搞一下,树链剖分维护一下。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int _max(int x, int y) {return x > y ? x : y;}
const int maxn = 110000;
struct node {
int x, y, next;
} e[2 * maxn]; int len, last[maxn];
struct trnode {
int lc, rc, sum, max;
} t[20 * maxn]; int cnt, rt[maxn];
int id, tot[maxn], fa[maxn], son[maxn], dep[maxn], top[maxn], ys[maxn];
int w[maxn], cc[maxn];
char ss[11];
void ins(int x, int y) {
e[++len].x = x; e[len].y = y;
e[len].next = last[x]; last[x] = len;
}
void pre_tree_node(int x) {
son[x] = 0; tot[x] = 1;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(y != fa[x]) {
fa[y] = x;
dep[y] = dep[x] + 1;
pre_tree_node(y);
tot[x] += tot[y];
if(tot[son[x]] < tot[y]) son[x] = y;
}
}
}
void pre_tree_edge(int x, int tp) {
top[x] = tp; ys[x] = ++id;
if(son[x]) pre_tree_edge(son[x], tp);
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(y != fa[x] && y != son[x]) pre_tree_edge(y, y);
}
}
void Link(int &u, int l, int r, int p, int c) {
if(!u) u = ++cnt;
t[u].sum += c; t[u].max = _max(t[u].max, c);
if(l == r) return ;
int mid = (l + r) / 2;
if(p <= mid) Link(t[u].lc, l, mid, p, c);
else Link(t[u].rc, mid + 1, r, p, c);
}
void del(int u, int l, int r, int p) {
if(l == r) {
t[u].sum = t[u].max = 0;
return ;
}
int mid = (l + r) / 2;
if(p <= mid) del(t[u].lc, l, mid, p);
else del(t[u].rc, mid + 1, r, p);
t[u].sum = t[t[u].lc].sum + t[t[u].rc].sum;
t[u].max = _max(t[t[u].lc].max, t[t[u].rc].max);
}
int findsum(int u, int l, int r, int ll, int rr) {
if(!u) return 0;
if(l == ll && r == rr) return t[u].sum;
int mid = (l + r) / 2;
if(rr <= mid) return findsum(t[u].lc, l, mid, ll, rr);
else if(ll > mid) return findsum(t[u].rc, mid + 1, r, ll, rr);
else return findsum(t[u].lc, l, mid, ll, mid) + findsum(t[u].rc, mid + 1, r, mid + 1, rr);
}
int findmax(int u, int l, int r, int ll, int rr) {
if(!u) return 0;
if(l == ll && r == rr) return t[u].max;
int mid = (l + r) / 2;
if(rr <= mid) return findmax(t[u].lc, l, mid, ll, rr);
else if(ll > mid) return findmax(t[u].rc, mid + 1, r, ll, rr);
else return _max(findmax(t[u].lc, l, mid, ll, mid), findmax(t[u].rc, mid + 1, r, mid + 1, rr));
}
int solve1(int x, int y, int c) {
int tx = top[x], ty = top[y], ans = 0;
while(tx != ty) {
if(dep[tx] > dep[ty]) swap(tx, ty), swap(x, y);
ans += findsum(rt[c], 1, id, ys[ty], ys[y]);
y = fa[ty]; ty = top[y];
}
if(dep[x] > dep[y]) swap(x, y);
ans += findsum(rt[c], 1, id, ys[x], ys[y]);
return ans;
}
int solve2(int x, int y, int c) {
int tx = top[x], ty = top[y], ans = 0;
while(tx != ty) {
if(dep[tx] > dep[ty]) swap(tx, ty), swap(x, y);
ans = _max(ans, findmax(rt[c], 1, id, ys[ty], ys[y]));
y = fa[ty]; ty = top[y];
}
if(dep[x] > dep[y]) swap(x, y);
ans = _max(ans, findmax(rt[c], 1, id, ys[x], ys[y]));
return ans;
}
int main() {
int n, m; scanf("%d%d", &n, &m);
pre_tree_node(1);
for(int i = 1; i <= n; i++) scanf("%d%d", &w[i], &cc[i]);
for(int i = 1; i < n; i++) {
int x, y; scanf("%d%d", &x, &y);
ins(x, y); ins(y, x);
}
pre_tree_node(1);
pre_tree_edge(1, 1);
for(int i = 1; i <= n; i++) Link(rt[cc[i]], 1, id, ys[i], w[i]);
for(int i = 1; i <= m; i++) {
scanf("%s", ss + 1);
if(ss[1] == 'C') {
int x, c; scanf("%d%d", &x, &c);
del(rt[cc[x]], 1, id, ys[x]);
if(ss[2] == 'C') {
cc[x] = c;
Link(rt[c], 1, id, ys[x], w[x]);
}
else {
w[x] = c;
Link(rt[cc[x]], 1, id, ys[x], c);
}
}
else {
int x, y; scanf("%d%d", &x, &y);
if(ss[2] == 'S') printf("%d\n", solve1(x, y, cc[x]));
else printf("%d\n", solve2(x, y, cc[x]));
}
}
return 0;
}