P2934 [USACO09JAN] Safe Travel G
题意:P2934 [USACO09JAN] Safe Travel G。
简要题意:
解法:
首先介绍最短路树。
考虑求出从
这个图有
考虑将这棵树视为以
现在考虑原题。相当于我要删掉每条边,设这条边的两个端点较深的是
证明:
假如我们走进了
其次,假如在进入
证毕。
那只要考虑枚举每条非树边
特别注意,
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <cassert>
#include <map>
using namespace std;
const int N = 2e5 + 5;
int n, m;
vector<pair<int, int>> G[N];
vector<int> NG[N];
int pre[N];
int dis[N];
bool vis[N];
struct Node
{
int u, d;
Node(int u, int d) :u(u), d(d) {}
Node() = default;
bool operator<(const Node& g) const
{
return d > g.d;
}
};
int fa[N][20];
int dep[N];
void dfs(int u, int f)
{
dep[u] = dep[f] + 1;
fa[u][0] = f;
for (auto& j : NG[u]) if (j ^ f) dfs(j, u);
}
struct Edge
{
int u, v, w;
Edge() = default;
Edge(int u, int v, int w) :u(u), v(v), w(w) {}
};
bool chk[N];
class Dsu
{
public:
int f[N];
void Init()
{
for (int i = 1; i <= n; i++) f[i] = fa[i][0];
}
int find(int u)
{
if (u == 0) return u;
if (!chk[f[u]]) return f[u];
return f[u] = find(f[u]);
}
}dsu;
int ans[N];
int u[N], v[N], w[N];
int main()
{
ios::sync_with_stdio(0), cin.tie(0);
memset(dis, 0x3f, sizeof dis);
memset(ans, 0x3f, sizeof ans);
cin >> n >> m;
for (int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
::u[i] = u, ::v[i] = v, ::w[i] = w;
G[u].emplace_back(make_pair(v, w));
G[v].emplace_back(make_pair(u, w));
}
auto dijkstra = [&](int st)->void
{
priority_queue<Node> q;
dis[st] = 0;
q.push(Node(st, 0));
while (q.size())
{
auto [u, d] = q.top();
q.pop();
if (vis[u]) continue;
vis[u] = 1;
for (auto& [j, w] : G[u])
{
if (dis[j] > dis[u] + w)
{
pre[j] = u;
dis[j] = dis[u] + w;
q.push(Node(j, dis[j]));
}
}
}
};
dijkstra(1);
for (int i = 2; i <= n; i++) NG[pre[i]].emplace_back(i);
dfs(1, 0);
auto Init = [&]()->void
{
for (int j = 1; j <= 19; j++)
{
for (int i = 1; i <= n; i++) fa[i][j] = fa[fa[i][j - 1]][j - 1];
}
};
Init();
auto LCA = [&](int u, int v)->int
{
if (u == v) return u;
if (dep[u] < dep[v]) swap(u, v);
int c = 0, k = dep[u] - dep[v];
while (k)
{
if (k & 1) u = fa[u][c];
c++;
k >>= 1;
}
if (u == v) return u;
for (int i = 19; i >= 0; i--) if (fa[u][i] ^ fa[v][i]) u = fa[u][i], v = fa[v][i];
return fa[u][0];
};
vector<Edge> ve;
for (int i = 1; i <= m; i++)
{
int u = ::u[i], v = ::v[i], w = ::w[i];
int nval = dis[u] + dis[v] + w;
ve.emplace_back(Edge(u, v, nval));
}
sort(ve.begin(), ve.end(), [&](const auto& h, const auto& x) {return h.w < x.w; });
dsu.Init();
for (auto& [u, v, w] : ve)
{
if (pre[u] == v || pre[v] == u) continue;
if (dep[u] > dep[v]) swap(u, v);
int k = LCA(u, v);
if (k != u)
{
if (!chk[u])
{
chk[u] = 1;
ans[u] = w;
}
}
if (k != v && !chk[v]) chk[v] = 1, ans[v] = w;
int j = u;
while (true)
{
int p = dsu.find(j);
if (!p || dep[p] <= dep[k]) break;
chk[p] = 1, ans[p] = w;
}
j = v;
while (true)
{
int p = dsu.find(j);
if (!p || dep[p] <= dep[k]) break;
chk[p] = 1, ans[p] = w;
}
}
for (int i = 2; i <= n; i++)
{
if (ans[i] == ans[0]) cout << "-1\n";
else cout << ans[i] - dis[i] << "\n";
}
return 0;
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析