Description:
S
S
国有个城市,编号从
1
1
到。城市间用
N−1
N
−
1
条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教,
S
S
国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
在S国的历史上常会发生以下几种事件:
”CCxc”:
”
C
C
x
c
”
:
城市x的居民全体改信了
c
c
教;
城市x的评级调整为
w;
w
;
”QSxy”:
”
Q
S
x
y
”
:
一位旅行者从城市
x
x
出发,到城市,并记下了途中留宿过的城市的评级总和;
”QMxy”:
”
Q
M
x
y
”
:
一位旅行者从城市
x
x
出发,到城市,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。
Solution:
树链剖分+动态开点线段树裸题。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 +5;
int n, q, dfs_clock, cnt;
int w[N], c[N], mir[N], sum[N * 30], mx[N * 30], lc[N * 30], rc[N * 30], root[N], sz[N], son[N], dfn[N], top[N], dep[N], fa[N];
vector<int> G[N];
void update(int l, int r, int &x, int p, int d) {
if(!x) {
x = ++cnt;
}
if(l == r) {
mx[x] = sum[x] = d;
return;
}
int mid = (l + r) >> 1;
if(p <= mid) {
update(l, mid, lc[x], p, d);
} else {
update(mid + 1, r, rc[x], p, d);
}
sum[x] = sum[lc[x]] + sum[rc[x]];
mx[x] = max(mx[lc[x]], mx[rc[x]]);
}
int query_sum(int l, int r, int x, int a, int b) {
if(l > b || r < a) {
return 0;
}
if(l >= a && r <= b) {
return sum[x];
}
int mid = (l + r) >> 1;
return query_sum(l, mid, lc[x], a, b) + query_sum(mid + 1, r, rc[x], a, b);
}
int query_mx(int l, int r, int x, int a, int b) {
if(l > b || r < a) {
return 0;
}
if(l >= a && r <= b) {
return mx[x];
}
int mid = (l + r) >> 1;
return max(query_mx(l, mid, lc[x], a, b), query_mx(mid + 1, r, rc[x], a, b));
}
void dfs(int u, int last) {
sz[u] = 1;
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if(v == last) {
continue;
}
dep[v] = dep[u] + 1;
fa[v] = u;
dfs(v, u);
sz[u] += sz[v];
if(sz[v] > sz[son[u]]) {
son[u] = v;
}
}
}
void dfs(int u, int last, int acs) {
dfn[u] = ++dfs_clock;
mir[dfn[u]] = u;
top[u] = acs;
if(son[u]) {
dfs(son[u], u, acs);
}
for(int i = 0; i < G[u].size(); ++i) {
int v = G[u][i];
if(v == last || v == son[u]) {
continue;
}
dfs(v, u, v);
}
}
int main() {
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; ++i) {
scanf("%d%d", &w[i], &c[i]);
}
for(int i = 1; i < n; ++i) {
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
dfs(1, 0, 1);
for(int i = 1; i <= n; ++i) {
update(1, n, root[c[mir[i]]], i, w[mir[i]]);
}
while(q--) {
char opt[4];
int u, v;
scanf("%s%d%d", opt, &u, &v);
if(opt[0] == 'C' && opt[1] == 'C') {
update(1, n, root[c[u]], dfn[u], 0);
update(1, n, root[v], dfn[u], w[u]);
c[u] = v;
} else if(opt[0] == 'C' && opt[1] == 'W') {
update(1, n, root[c[u]], dfn[u], v);
w[u] = v;
} else if(opt[0] == 'Q' && opt[1] == 'S') {
int ret = 0, p = c[u];
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) {
swap(u, v);
}
ret += query_sum(1, n, root[p], dfn[top[u]], dfn[u]);
u = fa[top[u]];
}
if(dfn[u] > dfn[v]) {
swap(u, v);
}
ret += query_sum(1, n, root[p], dfn[u], dfn[v]);
printf("%d\n", ret);
} else {
int ret = 0, p = c[u];
while(top[u] != top[v]) {
if(dep[top[u]] < dep[top[v]]) {
swap(u, v);
}
ret = max(ret, query_mx(1, n, root[p], dfn[top[u]], dfn[u]));
u = fa[top[u]];
}
if(dfn[u] > dfn[v]) {
swap(u, v);
}
ret = max(ret, query_mx(1, n, root[p], dfn[u], dfn[v]));
printf("%d\n", ret);
}
}
return 0;
}