>Link
luogu CF1473E
>Description
给出一张
n
n
n 个点
m
m
m 条边的无向图
规定最短路的定义为:这条路径上的权值之和,减去最大权值,加上最小权值
求
1
1
1 到其他所有的点的最短路
n , m ≤ 2 ∗ 1 0 5 n,m\le 2*10^5 n,m≤2∗105
>解题思路
这种在一条路上对路径的权值操作的,想到分层图最短路
考虑最大权值、最小权值怎么搞,发现题意等同于「这条路径上的权值之和,减去一条边的权值,加上一条边权值」,因为这样求最短路,最优的情况肯定是「减去最大权值,加上最小权值」
那我们就把点分成三层,第一层到第二层建权值为 0 的边,表示减去这条边的权值,第二层到第三层建权值为
2
∗
w
2*w
2∗w 的边,表示加上这条边的权值。每层内仍然正常建边
然后跑第一层的 1 到第三层的最短路
但是发现这样还是不行,因为这样建图就默认了这条路径的最大值在最小值的前面,还有最大值在最小值的后面的情况
那就第一层和第二层之间、第二层和第三层之间反着建,再跑一次就行了
>代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#define N 600010
#define LL long long
using namespace std;
struct node
{
int id; LL ds;
friend bool operator < (node aa, node bb)
{
return aa.ds > bb.ds;
}
};
priority_queue<node> Q;
struct edge
{
int to, nxt; LL w;
} e[2000010];
int n, m, cnt, h[N], U[N], V[N];
LL dis[N], ans[N], W[N];
bool vis[N];
void add (int u, int v, LL w)
{
e[++cnt] = (edge){v, h[u], w};
h[u] = cnt;
// e[++cnt] = (edge){u, h[v], w};
// h[v] = cnt;
}
void dij ()
{
node u; int v;
memset (dis, 0x7f, sizeof (dis));
memset (vis, 0, sizeof (vis));
Q.push ((node){1, 0}); dis[1] = 0;
while (!Q.empty())
{
u = Q.top();
Q.pop();
if (vis[u.id]) continue;
vis[u.id] = 1;
for (int i = h[u.id]; i; i = e[i].nxt)
{
v = e[i].to;
if (!vis[v] && dis[u.id] + e[i].w < dis[v])
{
dis[v] = dis[u.id] + e[i].w;
Q.push ((node){v, dis[v]});
}
}
}
for (int i = 2; i <= n; i++)
{
ans[i] = min (ans[i], dis[i + 2 * n]);
ans[i] = min (ans[i], dis[i]);
}
}
int main()
{
int l;
scanf ("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
{
scanf ("%d%d%lld", &U[i], &V[i], &W[i]);
for (int j = 1; j <= 3; j++)
{
l = (j - 1) * n;
add (l + U[i], l + V[i], W[i]);
add (l + V[i], l + U[i], W[i]);
}
add (U[i], V[i] + n, 0);
add (V[i], U[i] + n, 0);
add (U[i] + n, V[i] + 2 * n, 2 * W[i]);
add (V[i] + n, U[i] + 2 * n, 2 * W[i]);
}
memset (ans, 0x7f, sizeof (ans));
dij ();
cnt = 0;
memset (h, 0, sizeof (h));
for (int i = 1; i <= m; i++)
{
for (int j = 1; j <= 3; j++)
{
l = (j - 1) * n;
add (l + U[i], l + V[i], W[i]);
add (l + V[i], l + U[i], W[i]);
}
add (U[i], V[i] + n, 2 * W[i]);
add (V[i], U[i] + n, 2 * W[i]);
add (U[i] + n, V[i] + 2 * n, 0);
add (V[i] + n, U[i] + 2 * n, 0);
}
dij ();
for (int i = 2; i <= n; i++)
printf ("%lld ", ans[i]);
return 0;
}