Codeforces 1473E Minimum Path 题解 [ 蓝 ] [ 分层图最短路 ] [ 贪心 ] [ 构造 ]
神仙分层图题。
不要考虑原式的实际含义,我们直接对整个式子考虑,设 \(e_{\max}\) 为最大边,\(e_{\min}\) 为最小边:
\[\sum\limits_{i=1}^{k}{w_{e_i}} - \max\limits_{i=1}^{k}{w_{e_i}} + \min\limits_{i=1}^{k}{w_{e_i}} = \sum\limits_{i=1, e_i\ne e_{\max}, e_i\ne e_{\min}}^{k}w_{e_i} + 2 \min\limits_{i=1}^{k}{w_{e_i}}
\]
容易发现我们把最大边的权值乘了一个 \(0\) 的系数,而把最小边的权值乘了一个 \(2\) 的系数。
发现当我们强制要求一定要有一条边权值乘 \(\bm 0\),另一条边权值乘 \(\bm 2\),求最短路的时候。我们乘 \(0\) 的一定是最大边,乘 \(2\) 的一定是最小边。
因此考虑建四层分层图:
- 第一层:没有乘 \(0, 2\)。
- 第二层:只乘了 \(0\)。
- 第三层:只乘了 \(2\)。
- 第四层:\(0, 2\) 都乘过了。
跑最短路即可。时间复杂度 \(O(n\log n)\)。
#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
using pl = pair<ll, int>;
const int N = 800005;
int n, m;
int getid(int x, int id)
{
return (id * n + x);
}
vector<pi> g[N];
void add(int u, int v, int w)
{
g[u].push_back({v, w});
}
void addeg(int u, int v, int w)
{
g[u].push_back({v, w});
g[v].push_back({u, w});
}
ll dis[N];
priority_queue<pl, vector<pl>, greater<pl> > q;
bitset<N> vis;
void Dijkstra()
{
memset(dis, 0x3f, sizeof(dis));
dis[getid(1, 0)] = 0;
q.push({0, getid(1, 0)});
while(!q.empty())
{
pl tmp = q.top();
q.pop();
int u = tmp.se;
if(vis[u]) continue;
vis[u] = 1;
for(auto eg : g[u])
{
int v = eg.fi, w = eg.se;
if(dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
q.push({dis[v], v});
}
}
}
}
int main()
{
//freopen("sample.in", "r", stdin);
//freopen("sample.out", "w", stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= m; i++)
{
int u, v, w;
cin >> u >> v >> w;
addeg(getid(u, 0), getid(v, 0), w);
addeg(getid(u, 1), getid(v, 1), w);
addeg(getid(u, 2), getid(v, 2), w);
addeg(getid(u, 3), getid(v, 3), w);
add(getid(u, 0), getid(v, 1), 0);
add(getid(v, 0), getid(u, 1), 0);
add(getid(u, 2), getid(v, 3), 0);
add(getid(v, 2), getid(u, 3), 0);
add(getid(u, 0), getid(v, 2), 2 * w);
add(getid(v, 0), getid(u, 2), 2 * w);
add(getid(u, 1), getid(v, 3), 2 * w);
add(getid(v, 1), getid(u, 3), 2 * w);
add(getid(u, 0), getid(v, 3), w);
add(getid(v, 0), getid(u, 3), w);
}
Dijkstra();
for(int i = 2; i <= n; i++) cout << dis[getid(i, 3)] << " ";
return 0;
}

浙公网安备 33010602011771号