传送门
题解:首先看清题意后,发现这道题和cf1473E挺像的,首先算出 d d d 值,跑个 b f s bfs bfs ,然后接着考虑 a n s [ i ] [ 0 / 1 ] ans[i][0/1] ans[i][0/1] 表示起点为 i i i 的路径中其中没有 2 2 2 操作和有 1 1 1 次 2 2 2 操作的路径中所能到达的最小的 d d d 值,所以更新其实还是简单的。考虑一条边为 i − > j i->j i−>j,那么
i f ( d [ i ] < d [ j ] ) a n s [ i ] [ 0 ] = m i n ( a n s [ i ] [ 0 ] , a n s [ j ] [ 0 ] ) , a n s [ i ] [ 1 ] = m i n ( a n s [ i ] [ 1 ] , a n s [ j ] [ 1 ] ) e l s e a n s [ i ] [ 1 ] = m i n ( a n s [ i ] [ 1 ] , a n s [ j ] [ 0 ] ) if(d[i]<d[j])\ ans[i][0]=min(ans[i][0],ans[j][0]),ans[i][1]=min(ans[i][1],ans[j][1])\\ else\ ans[i][1]=min(ans[i][1],ans[j][0])\\ if(d[i]<d[j]) ans[i][0]=min(ans[i][0],ans[j][0]),ans[i][1]=min(ans[i][1],ans[j][1])else ans[i][1]=min(ans[i][1],ans[j][0])
然后考虑建反图,之后把初值全部压进 s e t set set 中,然后开始不断地 s p f a spfa spfa 直到没有更新。
代码中 a n s [ i ] [ 0 ] ans[i][0] ans[i][0] 表示为 d [ i ] . f i r s t d[i].first d[i].first , a n s [ i ] [ 1 ] ans[i][1] ans[i][1] 表示为 d [ i ] . s e c o n d d[i].second d[i].second .
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
int main()
{
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
vector<int> g[n], rg[n];
for (int i = 0, u, v; i < m; i++) {
cin >> u >> v;
u--; v--;
g[u].emplace_back(v);
rg[v].emplace_back(u);
}
vector<int> dis(n);
vector<pair<int, int>> d(n, {
inf, inf});
queue<pair<int, int>> q;
d[0].first = 0;
dis[0] = 0;
set<pair<int, pair<int, int>>> s;
q.push({
0, 0});
s.insert({
0, {
0, 0}});
while (!q.empty()) {
int u = q.front().first, w = q.front().second;
q.pop();
for (auto x : g[u]) {
if (x == 0 || d[x].first != inf) {
continue;
} else {
d[x].first = w + 1;
dis[x] = d[x].first;
q.push({
x, d[x].first});
s.insert({
d[x].first, {
x, 0}});
}
}
}
while (!s.empty()) {
auto [u, f] = s.begin()->second;
s.erase(s.begin());
for (auto v : rg[u]) {
if (f == 0) {
if (dis[v] < dis[u]) {
if (d[v].first > d[u].first) {
auto it = s.find({
d[v].first, {
v, 0}});
if (it != s.end()){
s.erase(it);
}
d[v].first = d[u].first;
s.insert({
d[v].first, {
v, 0}});
}
}else {
if (d[v].second > d[u].first) {
auto it = s.find({
d[v].second, {
v, 1}});
if (it != s.end()){
s.erase(it);
}
d[v].second = d[u].first;
s.insert({
d[v].second, {
v, 1}});
}
}
} else {
if (dis[v] < dis[u]) {
if (d[v].second > d[u].second) {
auto it = s.find({
d[v].second, {
v, 1}});
if (it != s.end()){
s.erase(it);
}
d[v].second = d[u].second;
s.insert({
d[v].second, {
v, 1}});
}
}
}
}
}
for (auto x : d) {
cout << min(x.first, x.second) << " ";
}
cout << endl;
}
return 0;
}