题目大意:给一棵带权树,和一个集合S,初始为空。现有两种操作:
1、选择某个顶点加入S
2、将S中某个顶点去掉。
问:每次操作后,使得集合S中的点联通的最小边权和是多少。
思路:首先这道题可以用到一个公式,就是树上的点到某一个树链的距离,假设这个点是n,一条树链的两个端点是u, v,那么点到这条树链的距离
D = dist(n) - dist( lca(n, u) ) - dist( lca(n, v) ) + dist( lca(u, v) ),这一步可以画画图感受下。
有了这个铺垫就可以用它来解题了,首先预处理出每个结点的dfs序,以增加节点i为例,假设存在两个节点,且两个节点的dfs序恰好一个比i大一个比i小,那么增加的距离就是i到这条链的距离。
如果所有节点的dfs序都比i大或都比i小,那么取dfs序最大和最小的两个节点,那么增加的距离就是i到这条链的距离。
对于删除操作其实和增加操作等价,可以先删除这个节点然后按照增加节点来做即可。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<string>
#include<map>
#include<set>
#include<ctime>
#define eps 1e-6
#define LL long long
#define pii pair<int, int>
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
const int MAXN = 100100;
//const int INF = 0x3f3f3f3f;
int n, q, clk, tim[MAXN];
int dist[MAXN], pnt[MAXN], ans[4*MAXN], arc[MAXN];
bool vis[MAXN];
vector<int> G[MAXN], W[MAXN], query[MAXN], num[MAXN];
int Find(int x) {
if(x == pnt[x]) return x;
return pnt[x] = Find(pnt[x]);
}
void Tarjan(int u) {
vis[u] = 1; pnt[u] = u;
int sz1 = G[u].size();
for(int i = 0; i < sz1; i++) {
int v = G[u][i];
if(vis[v]) continue;
Tarjan(v);
pnt[v] = u;
}
int sz2 = query[u].size();
for(int i = 0; i < sz2; i++) {
int v = query[u][i];
if(vis[v]) ans[num[u][i]] = dist[Find(v)];
//cout << u << " " << i << " " << sz2 << endl;
}
}
void dfs(int cur, int fa, int val) {
tim[cur] = ++clk;
arc[clk] = cur;
dist[cur] = val;
for(int i = 0; i < G[cur].size(); i++) {
int u = G[cur][i];
if(u == fa) continue;
dfs(u, cur, val+W[cur][i]);
}
}
set<int> s;
void init() {
clk = 0;
s.clear();
memset(vis, 0, sizeof(vis));
for(int i = 1; i <= n; i++) {
G[i].clear();
W[i].clear();
query[i].clear();
num[i].clear();
}
}
int upd[MAXN];
int main() {
//freopen("input.txt", "r", stdin);
int T; cin >> T;
int kase = 0;
while(T--) {
cin >> n >> q;
init();
for(int i = 1, u, v, d; i < n; i++) {
scanf("%d%d%d", &u, &v, &d);
G[u].push_back(v);
G[v].push_back(u);
W[u].push_back(d);
W[v].push_back(d);
}
dfs(1, 0, 0);
for(int i = 1, u, v; i <= q; i++) {
scanf("%d%d", &u, &v);
if(u == 1) {
if(!s.count(tim[v])) {
if(s.empty()) {
s.insert(tim[v]);
upd[i] = 0;
}
else if(s.size() == 1) {
int t = *s.begin();
ans[4*i] = dist[arc[t]];
query[arc[t]].push_back(v);
num[arc[t]].push_back(4*i+1);
query[v].push_back(arc[t]);
num[v].push_back(4*i+1);
query[arc[t]].push_back(v);
num[arc[t]].push_back(4*i+2);
query[v].push_back(arc[t]);
num[v].push_back(4*i+2);
ans[4*i+3] = dist[v];
s.insert(tim[v]);
upd[i] = 1;
}
else {
int t1, t2;
if(tim[v]<*s.begin() || tim[v]>*s.rbegin()) t1 = *s.begin(), t2 = *s.rbegin();
else {
set<int>::iterator it1, it2;
it1 = s.upper_bound(tim[v]);
t2 = *it1;
it2 = --it1;
t1 = *it2;
}
query[arc[t1]].push_back(arc[t2]);
query[arc[t2]].push_back(arc[t1]);
num[arc[t1]].push_back(4*i);
num[arc[t2]].push_back(4*i);
query[v].push_back(arc[t1]);
query[arc[t1]].push_back(v);
num[v].push_back(4*i+1);
num[arc[t1]].push_back(4*i+1);
query[v].push_back(arc[t2]);
query[arc[t2]].push_back(v);
num[v].push_back(4*i+2);
num[arc[t2]].push_back(4*i+2);
ans[4*i+3] = dist[v];
s.insert(tim[v]);
upd[i] = 1;
}
}
else upd[i] = 0;
}
else {
if(s.count(tim[v])) {
s.erase(tim[v]);
if(s.empty()) {
upd[i] = 0;
}
else if(s.size() == 1) {
int t = *s.begin();
ans[4*i] = dist[arc[t]];
query[arc[t]].push_back(v);
num[arc[t]].push_back(4*i+1);
query[v].push_back(arc[t]);
num[v].push_back(4*i+1);
query[arc[t]].push_back(v);
num[arc[t]].push_back(4*i+2);
query[v].push_back(arc[t]);
num[v].push_back(4*i+2);
ans[4*i+3] = dist[v];
upd[i] = 2;
}
else {
int t1, t2;
if(tim[v]<*s.begin() || tim[v]>*s.rbegin()) t1 = *s.begin(), t2 = *s.rbegin();
else {
set<int>::iterator it1, it2;
it1 = s.upper_bound(tim[v]);
t2 = *it1;
it2 = --it1;
t1 = *it2;
}
query[arc[t1]].push_back(arc[t2]);
query[arc[t2]].push_back(arc[t1]);
num[arc[t1]].push_back(4*i);
num[arc[t2]].push_back(4*i);
query[v].push_back(arc[t1]);
query[arc[t1]].push_back(v);
num[v].push_back(4*i+1);
num[arc[t1]].push_back(4*i+1);
query[v].push_back(arc[t2]);
query[arc[t2]].push_back(v);
num[v].push_back(4*i+2);
num[arc[t2]].push_back(4*i+2);
ans[4*i+3] = dist[v];
upd[i] = 2;
}
}
else upd[i] = 0;
}
}
Tarjan(1);
printf("Case #%d:\n", ++kase);
int ret = 0;
for(int i = 1; i <= q; i++) {
if(!upd[i]) printf("%d\n", ret);
else if(upd[i] == 1) {
ret = ret + ans[i*4] - ans[i*4+1] - ans[i*4+2] + ans[i*4+3];
printf("%d\n", ret);
}
else {
ret = ret - ans[i*4] + ans[i*4+1] + ans[i*4+2] - ans[i*4+3];
printf("%d\n", ret);
}
}
}
return 0;
}