• CF567E President and Roads


    (color{#0066ff}{ 题目描述 })

    给出一个有向图,从起点走到终点(必须走最短路),问一条边是否一定会被经过,如果不经过它,可以减小它的多少边权使得经过它(边权不能减少到0)

    (color{#0066ff}{输入格式})

    第一行包含四个整数n,m,s和t((2 leq n leq 10^5; 1 leq m leq 10^5,1 leq s, t leq n)) -在BERLAND城市,道路的数量,首都和总统家乡(s  ≠  t)。

    接下来的m条线路包含道路。各道路被给定为一组三个整数ai, bi, li (1 ≤ ai, bi ≤ n; ai ≠ bi; 1 ≤ li ≤ (10^6)) -由连接在城市第i条道路以及骑行所需的时间。道路从城市a 直达城市b i。

    城市编号从1到n。每对城市之间可以有多条道路。保证沿着道路有从s到t的路径

    (color{#0066ff}{输出格式})

    打印m行。第i行应包含有关第i条道路的信息(道路按出现在输入中的顺序编号)。

    如果总统在旅行期间肯定会骑它,则该行必须包含一个单词“ 是 ”(没有引号)。

    否则,如果能够修复第i条道路,使其上的旅行时间保持正面,那么总统肯定会骑在它上面,打印空格分隔的单词“ CAN ”(不带引号)以及修复的最小费用。

    如果我们不能让总统肯定会骑在这条路上,请打印“ 否 ”(没有引号)。

    注意 修复道路的费用是修复前后骑车所需的时间之差。

    (color{#0066ff}{输入样例})

    6 7 1 6
    1 2 2
    1 3 10
    2 3 7
    2 4 8
    3 5 3
    4 5 2
    5 6 1
    
        
    3 3 1 3
    1 2 10
    2 3 10
    1 3 100
    
        
        
    2 2 1 2
    1 2 1
    1 2 2
    

    (color{#0066ff}{输出样例})

    YES
    CAN 2
    CAN 1
    CAN 1
    CAN 1
    CAN 1
    YES
    
    
    
    YES
    YES
    CAN 81
    
        
        
    YES
    NO
    

    (color{#0066ff}{数据范围与提示})

    none

    (color{#0066ff}{ 题解 })

    从S正向建图跑DIJ,从T反向建图跑DIJ

    考虑一个边,如果一定在最短路上首先用两端点dis+边权判断,然后如果是必经边,显然是最短路树上的割边

    然而好像写挂了qwq

    还有一种方法是利用最短路计数来算

    一条边必经,当且仅当(diss[x]+dist[y]+z=diss[t] &&cnts[x]*cntt[y]=cnts[t])

    但是cnt会炸LL

    于是开始取模

    然而这题TM还卡模数,调了好久

    对于非必经边,若让它必经,显然让它减小一些权值使得恰好比最短路小1就行了

    判断一下是否到0就行

    #include<bits/stdc++.h>
    #define LL long long
    #define int long long
    LL in() {
        char ch; LL x = 0, f = 1;
        while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
        for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
        return x * f;
    }
    using std::pair;
    using std::make_pair;
    const int mox = 998244353;
    const int mod = 1004535809;
    const int maxn = 1e5 + 200;
    const LL inf = 999999999999999LL;
    struct node {
        int to;
        LL dis;
        node *nxt;
        node(int to = 0, LL dis = 0, node *nxt = NULL): to(to), dis(dis), nxt(nxt) {}
        void *operator new(size_t) {
            static node *S = NULL, *T = NULL;
            return (S == T) && (T = (S = new node[1024]) + 1024), S++;
        }
    };
    struct E {
        LL x, y, z;
    }e[maxn];
    int n, m, S, T;
    node *head[maxn], *h[maxn];
    LL diss[maxn], dist[maxn], cnts[maxn], cntt[maxn], cntss[maxn], cnttt[maxn];
    bool vis[maxn];
    std::priority_queue<pair<LL, int>, std::vector<pair<LL, int> >, std::greater<pair<LL, int> > > q;
    void add(int from, int to, int dis, node **hh) {
        hh[from] = new node(to, dis, hh[from]);
    }
    void dij(int s, LL *dis, node **hh, LL *cnt, LL *ccnt) {
        for(int i = 1; i <= n; i++) dis[i] = inf, vis[i] = false;
        q.push(make_pair(dis[s] = 0, s));
        cnt[s] = 1;
        while(!q.empty()) {
            int tp = q.top().second; q.pop();
            if(vis[tp]) continue;
            vis[tp] = true;
            for(node *i = hh[tp]; i; i = i->nxt) {
                if(dis[i->to] > dis[tp] + i->dis)
                    q.push(make_pair(dis[i->to] = dis[tp] + i->dis, i->to)), cnt[i->to] = cnt[tp] % mod, ccnt[i->to] = ccnt[tp] % mox;
                else if(dis[i->to] == dis[tp] + i->dis) (cnt[i->to] += cnt[tp]) %= mod, (ccnt[i->to] += ccnt[tp]) %= mox;
            }
        }
    }
    signed main() {
        n = in(), m = in(), S = in(), T = in();
        for(int i = 1; i <= m; i++) {
            E &o = e[i];
            o.x = in(), o.y = in(), o.z = in();
            add(o.x, o.y, o.z, head);
            add(o.y, o.x, o.z, h);
        }
        dij(S, diss, head, cnts, cntss);
        dij(T, dist, h, cntt, cnttt);
        for(int i = 1; i <= m; i++) {
            E o = e[i];
            if(diss[o.x] + dist[o.y] + o.z == diss[T] && (cnts[o.x] * cntt[o.y] % mod) == (cnts[T] % mod) && (cntss[o.x] * cnttt[o.y] % mod) == (cntss[T] % mod)) printf("YES
    ");
            else {
                LL now = diss[o.x] + dist[o.y] + o.z;
                LL goal = diss[T] - 1;
    			LL dt = now - goal;
                if(o.z - dt <= 0) printf("NO
    ");
                else printf("CAN %lld
    ", dt);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    二维码的生成细节和原理【转】
    ASP.NET中的Session怎么正确使用
    Application,Session,Cookie,ViewState和Cache区别
    为什么 Rust 连续三年成为最受欢迎的语言
    《预见2050》:科技也很燃
    财讯传媒集团首席战略官段永朝:AI等技术将带来认知重启
    福特第三代自动驾驶在美开启公开道路测试
    2019百度AI开发者大会,百度华为将宣布大消息
    全球负载最大吨位搬运机器人在中国诞生
    selenium webdriver python 开始
  • 原文地址:https://www.cnblogs.com/olinr/p/10265544.html
Copyright © 2020-2023  润新知