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;
}

Thanks!

posted on 2020-08-24 08:51  PI_PJW  阅读(59)  评论(0)    收藏  举报

导航