P6227 [BalticOI 2019 Day1]山谷

先考虑能否逃出。

我们不妨设删去的边的两点编号为 u,vu,v,其中 uuvv 的父亲。

容易发现当且仅当 RRvv 的子树中时无法逃出,即 RRvv 的 LCA 为 vv。可以通过树剖等处理。

我们假设不能逃出,那么需要考虑能否到商店。因为已经无法逃出,那么 RR 可以走到 vv 的子树中的任意一个点。因此只需要处理 cuc_u 表示以 uu 为根的子树中商店个数,那么只需要判断 cvc_v 是否是正数即可。

假设 cv>0c_v > 0,那么我们需要求到最近商店的距离。我们设 fuf_u 表示 uu 到其子树中某个商店的最近距离,若没有商店,则 fu=inff_u = \inf。容易通过朴素的 DP 求出,即 fu=minjsonu(fj+w(u,j))f_u = \min \limits_{j \in son_u} (f_j + w(u, j))ww 是边权。

考虑 RR 能到的商店,分为两部分,一部分是在 RR 子树内的,显然直接求 fRf_R 即可。另一部分是在 vv 子树内,RR 子树外的。我们设 kkvRv \sim R 路径上的一个点,那么 kk 对答案的贡献是 fk+dis(k,R)f_k + dis(k, R)disdis 是两点之间边权和。

不妨设 dud_u 表示 uu 到根节点的边权和,由于 kkRR 的祖先,所以 dis(k,R)=dRdkdis(k, R) = d_R - d_k。贡献可转化为 fkdk+dRf_k - d_k + d_R。容易发现 dRd_R 不变。于是只需要求 fkdkf_k - d_k 最小值即可。树剖维护,使用 ST 表可以做到 O(nlogn)O(n \log n)。我的实现是 O(nlog2n)O(n \log^2 n) 的线段树。

除此之外,也可以用线性 RMQ 和线性 LCA 的黑科技优化到 O(n)O(n)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <climits>
using namespace std;

#define int long long

const int N = 1e5 + 5, INF = 1e15;

vector<pair<int, int> > G[N];

int n, s, q, e;
long long cnt[N], f[N], sum[N];
bool p[N];
long long val[N];
int U[N], V[N];

void dfs(int u, int fa, int v)
{
	sum[u] = sum[fa] + 1LL * v;
	cnt[u] = p[u];
	if (p[u])
	{
		f[u] = 0;
	}
	for (auto j : G[u])
	{
		if (j.first != fa)
		{
			dfs(j.first, u, j.second);
			cnt[u] += cnt[j.first];
			f[u] = min(f[u], f[j.first] + j.second);
		}
	}
}

class SegmentTree
{
public:
	struct Node
	{
		int l, r;
		long long minn;
	}tr[N << 2];
	void pushup(int u)
	{
		tr[u].minn = min(tr[u << 1].minn, tr[u << 1 | 1].minn);
	}
	void build(int u, int l, int r, long long* a)
	{
		tr[u] = { l, r, a[l] };
		if (l == r) return;
		int mid = l + r >> 1;
		build(u << 1, l, mid, a);
		build(u << 1 | 1, mid + 1, r, a);
		pushup(u);
	}
	long long query(int u, int l, int r)
	{
		if (tr[u].l >= l and tr[u].r <= r) return tr[u].minn;
		int mid = tr[u].l + tr[u].r >> 1;
		long long res = 1e18;
		if (l <= mid) res = query(u << 1, l, r);
		if (r > mid) res = min(res, query(u << 1 | 1, l, r));
		return res;
	}
};

class TreeCut
{
public:
	SegmentTree sgt;
	int id[N], sz[N], dep[N], fa[N], son[N], top[N], idx;
	long long na[N];
	void dfs1(int u, int f)
	{
		fa[u] = f;
		sz[u] = 1;
		dep[u] = dep[f] + 1;
		for (auto j : G[u])
		{
			if (j.first != f)
			{
				dfs1(j.first, u);
				sz[u] += sz[j.first];
				if (sz[son[u]] < sz[j.first]) son[u] = j.first;
			}
		}
	}
	void dfs2(int u, int tf)
	{
		top[u] = tf;
		id[u] = ++idx;
		na[idx] = val[u];
		if (!son[u]) return;
		dfs2(son[u], tf);
		for (auto j : G[u])
		{
			if (j.first != fa[u] && j.first != son[u]) dfs2(j.first, j.first);
		}
	}
	void Init()
	{
		dfs1(e, 0);
		dfs2(e, e);
		sgt.build(1, 1, n, na);
	}
	int LCA(int u, int v)
	{
		while (top[u] ^ top[v])
		{
			if (dep[top[u]] < dep[top[v]]) swap(u, v);
			u = fa[top[u]];
		}
		return (dep[u] < dep[v] ? u : v);
	}
	long long query(int u, int v)
	{
		long long res = 1e18;
		while (top[u] ^ top[v])
		{
			if (dep[top[u]] < dep[top[v]]) swap(u, v);
			res = min(res, sgt.query(1, id[top[u]], id[u]));
			u = fa[top[u]];
		}
		if (dep[u] < dep[v]) swap(u, v);
		res = min(res, sgt.query(1, id[v], id[u]));
		return res;
	}
}tc;

signed main()
{
	scanf("%lld%lld%lld%lld", &n, &s, &q, &e);
	f[n] = INF;
	for (int i = 1; i < n; i++)
	{
		f[i] = INF;
		int u, v, w;
		scanf("%lld%lld%lld", &u, &v, &w);
		G[u].emplace_back(make_pair(v, w));
		G[v].emplace_back(make_pair(u, w));
		U[i] = u, V[i] = v;
	}
	for (int i = 1; i <= s; i++)
	{
		int u;
		scanf("%lld", &u);
		p[u] = 1;
	}
	dfs(e, 0, 0);
	for (int i = 1; i <= n; i++)
	{
		val[i] = f[i] - sum[i];
	}
	tc.Init();
	while (q--)
	{
		int I, R;
		scanf("%lld%lld", &I, &R);
		int u = U[I], v = V[I];
		if (tc.fa[u] == v) swap(u, v);
		int lca = tc.LCA(R, v);
		if (lca != v)
		{
			printf("escaped\n");
		}
		else if (cnt[v] > 0)
		{
			long long va = tc.query(v, R);
			printf("%lld\n", va + sum[R]);
		}
		else
		{
			printf("oo\n");
		}
	}
	return 0;
}
posted @   HappyBobb  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示