P6227 [BalticOI 2019 Day1]山谷
先考虑能否逃出。
我们不妨设删去的边的两点编号为
容易发现当且仅当
我们假设不能逃出,那么需要考虑能否到商店。因为已经无法逃出,那么
假设
考虑
不妨设
除此之外,也可以用线性 RMQ 和线性 LCA 的黑科技优化到
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现