P5680 [GZOI2017]共享单车 题解
【模板】读题
本蒟蒻码量上 3k 的第二题
公司为了减少成本,回收时从区域 到任何一个区域 都选择长度最短的路径,如果有多条到某一个区域的最短路径,则选择所有最短路径中该区域的前一区域编号最小的一条路径,称这条路径为 到 的回收路线。所有的回收路线组成一棵树状结构,称之为回收路线树。
根据题意,回收路线树就是最短路径树
公司每次会回收若干个区域的单车,称这些区域为回收区域。 公司还将某些区域设为投放区域,称其余区域为非投放区域。在回收路线树上,标记出区域 ,标记出所有的回收区域,以及标记出任意两个回收区域在回收路线树上的最近公共祖先。
根据题意,标记
公司对 公司的回收行动造成了阻碍,当且仅当对任意一个 以外的被标记的投放区域 ,从区域 到 的回收路线上都存在两个被标记的区域,它们之间所有道路(回收路线树上两点路径)被阻碍。阻碍一条道路的代价为该道路的长度。
根据题意,求阻碍
维护
以操作
则有
注意清空。
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define P pair<int, int>
using namespace std;
struct G
{
struct E
{
int v, w, t;
} e[200050];
int c, h[50050];
void A(int u, int v, int w)
{
e[++c] = {v, w, h[u]};
h[u] = c;
}
} A, T, V;
bool t[50050], w[50050];
P r[50050];
priority_queue<P, vector<P>, greater<P>> q;
int n, m, s, O, p, a[50050], z[50050], b[50050], d[50050], f[50050][25], o[50050], W[50050], g[50050];
bool C(int x, int y) { return b[x] < b[y]; }
void D(int u)
{
b[u] = ++p;
for (int i = T.h[u], v; i; i = T.e[i].t)
if (!b[v = T.e[i].v])
{
d[v] = d[f[v][0] = u] + 1;
W[v] = W[u] + T.e[i].w;
for (int j = 1; f[v][j - 1]; ++j)
f[v][j] = f[f[v][j - 1]][j - 1];
D(v);
}
}
int L(int x, int y)
{
if (d[x] < d[y])
swap(x, y);
while (d[x] > d[y])
x = f[x][__lg(d[x] - d[y])];
if (x == y)
return x;
for (int k = __lg(d[x]); k >= 0; --k)
if (f[x][k] != f[y][k])
x = f[x][k], y = f[y][k];
return f[x][0];
}
void F(int u)
{
o[u] = 0;
for (int i = V.h[u], v; i; i = V.e[i].t)
F(v = V.e[i].v), o[u] += min(V.e[i].w, t[v] ? 1 << 30 : o[v]);
}
int main()
{
scanf("%d%d%d%d", &n, &m, &s, &O);
for (int i = 0, u, v, w; i < m; ++i)
scanf("%d%d%d", &u, &v, &w), A.A(u, v, w), A.A(v, u, w);
memset(g, 0x3f, sizeof g);
q.push({g[s] = 0, s});
while (!q.empty())
{
int u = q.top().second;
q.pop();
if (!w[u])
{
w[u] = 1;
for (int i = A.h[u], v; i; i = A.e[i].t)
if (g[v = A.e[i].v] > g[u] + A.e[i].w || g[v] == g[u] + A.e[i].w && r[v].first > u)
q.push({g[v] = g[r[v].first = u] + A.e[i].w, v}), r[v].second = A.e[i].w;
}
}
for (int i = 1; i <= n; ++i)
if (r[i].first)
T.A(r[i].first, i, r[i].second);
D(s);
for (int i = 0, r, k, c = 0, w = 1; i < O; ++i)
{
scanf("%d%d", &r, &k);
if (r)
{
for (int j = 0; j < c; ++j)
V.h[z[j]] = 0;
V.c = c = 0;
w = 1;
for (int j = 0; j < k; ++j)
scanf("%d", a + j);
a[k++] = s;
sort(a, a + k, C);
z[c++] = a[0];
for (int j = 1; j < k; ++j)
z[c++] = L(a[j], a[j - 1]), z[c++] = a[j];
sort(z, z + c, C);
c = unique(z, z + c) - z;
for (int j = 1, l; j < c; ++j)
l = L(z[j], z[j - 1]), V.A(l, z[j], W[z[j]] - W[l]);
for (int j = 0; j < c; ++j)
if (t[z[j]])
{
w = 0;
break;
}
if (w)
{
puts("-1");
continue;
}
F(z[0]);
printf("%d\n", o[z[0]]);
}
else
for (int j = 0, x; j < k; ++j)
scanf("%d", &x), t[x] ^= 1;
}
return 0;
}
顺便,这题题面
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具