CF567E President and Roads 最短路+建反边
一.题目
传送门
翻译:
给出一个有向图,从起点走到终点(必须走最短路),问一条边是否一定会被经过,如果不经过它,可以减小它的多少边权使得经过它(边权不能减少到0)
二.题解
显然,这道题目要用到建反图的思想。
先处理出起点和终点延正反边到每个点的距离和最短路的方案数
判断一条边要减少多少边权才能一定被使用,就计算起点和终点到这条边两端点的距离和加这条边的边权:
1.如果等于起点到终点的最短距离就将两端点的方案数乘起来:
①如果方案总数等于起点到终点最短路的方案数,那么这条边就可以不做任何改动;
②如果不等于,那么说明这条边可以被替换,就要将它减一。
2.如果大于最短路距离,就直接计算这条边需要减少多少边权才能被用上。
注意每条边的边权不能减为0
三.Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
#define LL long long
#define M 100005
const LL mod = 998244353;
const LL INF = 1ll << 50;
struct node {
int v;
LL Dis;
node (){};
node (int V, LL DIS){
v = V;
Dis = DIS;
}
bool operator < (const node& rhs) const{
return rhs.Dis < Dis;
}
};
struct edge {
int v, flag; LL w;
edge (){};
edge (int V, LL W, int Flag){
v = V;
w = W;
flag = Flag;
}
};
int n, m, s, t, U[M], V[M];
LL W[M], cnts[M], cntt[M], diss[M], dist[M];
bool vis[M];
vector <edge> G[M];
void Dijkstra (int st, int pos, LL *cnt, LL *dis){
memset (vis, 0, sizeof vis);
for (int i = 1; i <= n; i ++)
dis[i] = INF;
dis[st] = 0, cnt[st] = 1;
priority_queue <node> Q;
Q.push (node (st, 0));
while (! Q.empty()){
node f = Q.top ();
Q.pop ();
if (vis[f.v])
continue;
vis[f.v] = 1;
for (int i = 0; i < G[f.v].size(); i ++){
int v = G[f.v][i].v, flag = G[f.v][i].flag; LL w = G[f.v][i].w;
if (flag != pos)
continue;
if (w + f.Dis == dis[v]){
cnt[v] = (cnt[v] + cnt[f.v]) % mod;
}
else if (w + f.Dis < dis[v]){
cnt[v] = cnt[f.v];
dis[v] = w + f.Dis;
if (! vis[v])
Q.push (node (v, dis[v]));
}
}
}
}
int main (){
scanf ("%d %d %d %d", &n, &m, &s, &t);
for (int i = 1; i <= m; i ++){
scanf ("%d %d %lld", &U[i], &V[i], &W[i]);
G[U[i]].push_back (edge (V[i], W[i], 0));
G[V[i]].push_back (edge (U[i], W[i], 1));
}
Dijkstra (s, 0, cnts, diss);
Dijkstra (t, 1, cntt, dist);
for (int i = 1; i <= m; i ++){
if (diss[U[i]] + diss[V[i]] >= INF)
printf ("NO\n");
else if (diss[U[i]] + W[i] + dist[V[i]] == diss[t]){
if ((cnts[U[i]] * cntt[V[i]]) % mod == cnts[t])
printf ("YES\n");
else{
if (W[i] > 1)
printf ("CAN 1\n");
else
printf ("NO\n");
}
}
else{
LL now = diss[U[i]] + W[i] + dist[V[i]] - diss[t] + 1;
if (W[i] > now)
printf ("CAN %lld\n", now);
else
printf ("NO\n");
}
}
return 0;
}
浙公网安备 33010602011771号