【刷题笔记】p10930 异象石

思路

首先注意到一个非常难注意到的性质:
将所有有异象石的点按时间戳进行排序,算出每个 \(a_i,a_{i+1}\) 在树上的最短路径和 \(a_n,a_1\) 在树上的最短路径的和,这个和就是第三种询问答案的二倍。
维护一个 set。
若加入 x 号点,它在 set 中左边的点是 l,右边是 r。则在加入时,断开 l->r,加入 l->x 与 x->r。
若删除 x 号点,同理,断开 l->x 与 x->r,加入 l->r。

#include<bits/stdc++.h>
#define N 100010
#define INF 2147483647
#define int long long
using namespace std;
int n, cnt = 0, head[N], q;
int dep[N], d[N], f[N][30], dfn[N], tim = 0, Dfs[N], ans = 0;
set<int>st;
struct edge{
	int to, next, w;
}e[N << 2];
void add(int x, int y, int w){
	e[++cnt].to = y;
	e[cnt].w = w;
	e[cnt].next = head[x];
	head[x] = cnt;
}
void dfs(int u, int fa){
	dfn[u] = ++tim, Dfs[tim] = u;
	f[u][0] = fa, dep[u] = dep[fa] + 1;
	for(int i = 1; i <= 20; i++){
		f[u][i] = f[f[u][i - 1]][i - 1];
	}
	for(int i = head[u]; i; i = e[i].next){
		int v = e[i].to, w = e[i].w;
		if(v == fa) continue;
		d[v] = d[u] + w;
		dfs(v, u);
	}
}
int Lca(int x, int y){
	if(dep[x] < dep[y]) swap(x, y);
	int len = dep[x] - dep[y];
	for(int i = 0; i <= 20; i++){
		if(len & 1) x = f[x][i];
		len >>= 1;
	}
	if(x == y) return x;
	for(int i = 20; i >= 0; i--){
		if(f[x][i] != f[y][i])
			x = f[x][i], y = f[y][i];
	}
	return f[x][0];
}
int calc(int x, int y){
	return d[x] + d[y] - 2 * d[Lca(x, y)];
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0); cout.tie(0);
	cin >> n;
	int x, y, w;
	for(int i = 1; i < n; i++){
		cin >> x >> y >> w;
		add(x, y, w), add(y, x, w);
	}
	dfs(1, 0); st.insert(-INF), st.insert(INF);
	cin >> q;
	while(q--){
		char op; int x;
		cin >> op;
		if(op == '+'){
			cin >> x; 
			auto it = st.lower_bound(dfn[x]);
			int r = *it, l = *(--it);
			if(l != -INF) ans += calc(Dfs[l], x);
			if(r != INF) ans += calc(x, Dfs[r]);
			if(l != -INF && r != INF) ans -= calc(Dfs[l], Dfs[r]);
			st.insert(dfn[x]);
		}
		if(op == '-'){
			cin >> x;
			st.erase(dfn[x]);
			auto it = st.lower_bound(dfn[x]);
			int r = *it, l = *(--it);
			if(l != -INF) ans -= calc(Dfs[l], x);
			if(r != INF) ans -= calc(x, Dfs[r]);
			if(l != -INF && r != INF) ans += calc(Dfs[l], Dfs[r]);
		}
		if(op == '?'){
			if(st.size() <= 3) cout << 0 << endl;
			else cout << (ans + calc(Dfs[*st.upper_bound(-INF)], Dfs[*(--st.lower_bound(INF))])) / 2 << endl;
		}
	}
	return 0;
}
posted @ 2025-05-20 14:24  GuoSN0410  阅读(8)  评论(0)    收藏  举报