【BZOJ3991】【SDOI2015】寻宝游戏

本文介绍了一种使用LCA算法求解树上两点间最短路径的方法,并结合动态维护策略解决了一系列涉及节点插入删除的问题。通过实例演示了如何在不断变化的树结构中高效更新节点间的距离。

【题目链接】

【思路要点】

  • 补档博客,无题解。

【代码】

#include<bits/stdc++.h>
using namespace std;
#define MAXN	100005
#define MAXLOG	20
struct edge {int dest; long long len; };
struct info {int value; };
vector <edge> a[MAXN];
set <info> BBT;
long long dist[MAXN];
int timer, dfn[MAXN], depth[MAXN], father[MAXN][MAXLOG];
void init(int pos, int fa, int dep, long long length) {
	depth[pos] = dep;
	father[pos][0] = fa;
	dist[pos] = length;
	dfn[pos] = ++timer;
	for (int i = 1; i < MAXLOG; i++)
		father[pos][i] = father[father[pos][i - 1]][i - 1];
	for (unsigned i = 0; i < a[pos].size(); i++)
		if (a[pos][i].dest != fa) init(a[pos][i].dest, pos, dep + 1, length + a[pos][i].len);
} 
int lca(int x, int y) {
	if (depth[x] < depth[y]) swap(x, y);
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (depth[father[x][i]] >= depth[y]) x = father[x][i];
	if (x == y) return x;
	for (int i = MAXLOG - 1; i >= 0; i--)
		if (father[x][i] != father[y][i]) {
			x = father[x][i];
			y = father[y][i];
		}
	return father[x][0];
}
long long length(int x, int y) {
	return dist[x] + dist[y] - dist[lca(x, y)] * 2;
}
bool operator < (info x, info y) {
	return dfn[x.value] < dfn[y.value];
}
bool operator > (info x, info y) {
	return dfn[x.value] > dfn[y.value];
}
int func(info tmp) {
	set <info> :: iterator tnp;
	tnp = BBT.end(); tnp--;
	if (*tnp < tmp) return (*tnp).value;
	tnp = BBT.lower_bound(tmp); tnp--;
	return (*tnp).value;
}
int main() {
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 1; i < n; i++) {
		int x, y, z;
		scanf("%d%d%d", &x, &y, &z);
		a[x].push_back((edge){y, z});
		a[y].push_back((edge){x, z});
	}
	init(1, 0, 1, 0);
	long long ans = 0;
	for (int i = 1; i <= m; i++) {
		info tmp;
		scanf("%d", &tmp.value);
		if (BBT.empty()) {
			BBT.insert(tmp);
			printf("0\n");
			continue;
		}
		if (BBT.count(tmp)) {
			BBT.erase(tmp);
			if (BBT.empty()) {
				printf("0\n");
				continue;
			}
			set <info> :: iterator tnp;
			tnp = BBT.end(); tnp--;
			if (*BBT.begin() < tmp) ans -= length(func(tmp), tmp.value);
			else ans -= length((*tnp).value, tmp.value);
			if (*tnp > tmp) ans -= length((*BBT.lower_bound(tmp)).value, tmp.value);
			else ans -= length((*BBT.begin()).value, tmp.value);
			if (*BBT.begin() < tmp && *tnp > tmp) ans += length(func(tmp), (*BBT.lower_bound(tmp)).value);
			else if (*BBT.begin() < tmp) ans += length(func(tmp), (*BBT.begin()).value);
			     else ans += length((*tnp).value, (*BBT.lower_bound(tmp)).value);
		} else {
			if (BBT.empty()) {
				BBT.insert(tmp);
				printf("0\n");
				continue;
			}
			set <info> :: iterator tnp;
			tnp = BBT.end(); tnp--;
			if (*BBT.begin() < tmp) ans += length(func(tmp), tmp.value);
			else ans += length((*tnp).value, tmp.value);
			if (*tnp > tmp) ans += length((*BBT.lower_bound(tmp)).value, tmp.value);
			else ans += length((*BBT.begin()).value, tmp.value);
			if (*BBT.begin() < tmp && *tnp > tmp) ans -= length(func(tmp), (*BBT.lower_bound(tmp)).value);
			else if (*BBT.begin() < tmp) ans -= length(func(tmp), (*BBT.begin()).value);
			     else ans -= length((*tnp).value, (*BBT.lower_bound(tmp)).value);
			BBT.insert(tmp);
		}
		printf("%lld\n", ans);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值