题目链接:hdu 5296 Annoying problem
先求出dfs序,然后每次修改一个节点u,找到dfs最接近u的两个点,a,b的dfs序分别大于和小于u的。修改值即为dp[u] - dp[lca(a,u)] - dp[lca(b,u)] + dp[lca(a, b)],dp[i]表示i到根节点的权值和。但集合中的节点的dfs序都大于或小于u时,a,b即用最大和最小的即可。
#include <cstdio>
#include <cstring>
#include <set>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 100005;
typedef set<int>::iterator iter;
set<int> S;
int N, Q, dp[maxn], vis[maxn];
int E, first[maxn], jump[maxn * 2], link[maxn * 2], val[maxn * 2];
int id, idx[maxn], ridx[maxn], dep[maxn], top[maxn], far[maxn], son[maxn], cnt[maxn];
inline void addEdge(int u, int v, int w) {
link[E] = v;
val[E] = w;
jump[E] = first[u];
first[u] = E++;
}
void dfs (int u, int pre, int d, int w) {
far[u] = pre;
dep[u] = d;
cnt[u] = 1;
son[u] = 0;
dp[u] = w;
for (int i = first[u]; i + 1; i = jump[i]) {
int v = link[i];
if (v == pre)
continue;
dfs(v, u, d + 1, w + val[i]);
cnt[u] += cnt[v];
if (cnt[son[u]] < cnt[v])
son[u] = v;
}
}
void dfs (int u, int rot) {
top[u] = rot;
if (son[u])
dfs(son[u], rot);
for (int i = first[u]; i + 1; i = jump[i]) {
int v = link[i];
if (v == far[u] || v == son[u])
continue;
dfs(v, v);
}
idx[u] = ++id;
ridx[id] = u;
}
int LCA (int u, int v) {
int p = top[u], q = top[v];
while (p != q) {
if (dep[p] < dep[q]) {
swap(p, q);
swap(u, v);
}
u = far[p];
p = top[u];
}
if (dep[u] > dep[v])
swap(u, v);
return u;
}
void init () {
S.clear();
scanf("%d%d", &N, &Q);
id = E = 0;
memset(first, -1, sizeof(first));
memset(vis, 0, sizeof(vis));
int u, v, w;
for (int i = 1; i < N; i++) {
scanf("%d%d%d", &u, &v, &w);
addEdge(u, v, w);
addEdge(v, u, w);
}
dfs(1, 0, 0, 0);
dfs(1, 1);
}
int solve (int u) {
if (S.size() == 0)
return 0;
int a, b;
iter mv = S.upper_bound(idx[u]);
if (mv == S.begin() || mv == S.end()) {
a = ridx[*S.begin()];
b = ridx[*S.rbegin()];
} else {
a = ridx[*mv];
mv--;
b = ridx[*mv];
}
return dp[u] - dp[LCA(u, a)] - dp[LCA(u, b)] + dp[LCA(a, b)];
}
int main () {
int cas;
scanf("%d", &cas);
for (int kcas = 1; kcas <= cas; kcas++) {
init();
printf("Case #%d:\n", kcas);
int k, u, ans = 0;
for (int i = 0; i < Q; i++) {
scanf("%d%d", &k, &u);
if (k == 1 && vis[idx[u]] == 0) {
ans += solve(u);
S.insert(idx[u]);
vis[idx[u]] = 1;
}
if (k == 2 && vis[idx[u]]) {
S.erase(idx[u]);
vis[idx[u]] = 0;
ans -= solve(u);
}
printf("%d\n", ans);
}
}
return 0;
}