[最短路图] Codeforces 1650G

题目大意

给定一张 \(n\) 个点 \(m\) 条边的无向图,设 \(s\)\(t\) 的最短路长度为 \(x\),求 \(s\)\(t\) 长度不超过 \(x+1\) 的路径条数,对 \(10^9+7\) 取模。\((n,m\leq 2\times 10^5)\)

题解

先跑一遍 dijkstra,求出最短路图。容易发现,长度比最短路长度多 \(1\) 的路径一定恰好存在一条边\((u,v)\)不在最短路图上,剩下的边全部在最短路图上,并且 \(dis(u)=dis(v)\)。我们先计算出在最短路图上从 \(s\) 出发到每个点的简单路径条数 \(dp_s[u]\),以及在最短路图上从 \(t\) 出发到每个点的简单路径条数 \(dp_t[u]\),然后枚举不在最短路图上且满足 \(dis(u)=dis(v)\) 的边 \((u,v)\),将\(dp_s[u]\times dp_t[v]+dp_s[v]\times dp_t[u]\) 累加到答案即可。

Code

#include <bits/stdc++.h>
using namespace std;

#define LL long long

template<typename elemType>
inline void Read(elemType& T) {
    elemType X = 0, w = 0; char ch = 0;
    while (!isdigit(ch)) { w |= ch == '-';ch = getchar(); }
    while (isdigit(ch)) X = (X << 3) + (X << 1) + (ch ^ 48), ch = getchar();
    T = (w ? -X : X);
}

const int maxn = 200010;
const LL MOD = 1e9 + 7;

int T, n, m, s, t;

struct Graph {
    struct edge { int Next, to, w; };
    edge G[maxn << 1];
    int head[maxn];
    int cnt;

    Graph() :cnt(2) {}
    void clear(int n) {
        cnt = 2;fill(head, head + n + 2, 0);
    }
    void add_edge(int u, int v) {
        G[cnt].w = 0;
        G[cnt].to = v;
        G[cnt].Next = head[u];
        head[u] = cnt++;
    }
};
Graph G;

struct Node { int Value, ID; };
struct cmpA { bool operator()(Node A, Node B) { return A.Value > B.Value; } };
priority_queue<Node, vector<Node>, cmpA> Q;
int dis[maxn];
bool vis[maxn];

void Dijkstra(int st) {
    for (int i = 1;i <= n;++i) {
        dis[i] = 0x3f3f3f3f;
        vis[i] = false;
    }
    dis[st] = 0;Q.push((Node) { 0, st });
    while (!Q.empty()) {
        int u = Q.top().ID;Q.pop();
        if (vis[u]) continue;
        vis[u] = true;
        for (int i = G.head[u];i;i = G.G[i].Next) {
            int v = G.G[i].to;
            if (vis[v]) continue;
            if (dis[v] > dis[u] + 1) {
                dis[v] = dis[u] + 1;
                Q.push((Node) { dis[v], v });
            }
        }
    }
}

void build_spg() {
    for (int u = 1;u <= n;++u) {
        for (int i = G.head[u];i;i = G.G[i].Next) {
            int v = G.G[i].to;
            if (dis[u] + 1 == dis[v])
                G.G[i].w = G.G[i ^ 1].w = 1;
        }
    }
}

LL dp_s[maxn], dp_t[maxn];
queue<int> Que;

void calc_dp(int st, LL* dp, int opt) {
    for (int i = 1;i <= n;++i) {
        vis[i] = false;
        dp[i] = 0;
    }
    dp[st] = 1; vis[st] = true; Que.push(st);
    while (!Que.empty()) {
        int u = Que.front(); Que.pop();
        for (int i = G.head[u];i;i = G.G[i].Next) {
            if (G.G[i].w == 0) continue;
            int v = G.G[i].to;
            if (dis[v] * opt > dis[u] * opt) dp[v] = (dp[v] + dp[u]) % MOD;
            if (!vis[v]) { vis[v] = true; Que.push(v); }
        }
    }
}

int main() {
    Read(T);
    while (T--) {
        Read(n); Read(m); Read(s); Read(t);
        G.clear(n);
        for (int i = 1;i <= m;++i) {
            int u, v;
            Read(u); Read(v);
            G.add_edge(u, v);
            G.add_edge(v, u);
        }
        Dijkstra(s);
        build_spg();
        calc_dp(s, dp_s, 1);
        calc_dp(t, dp_t, -1);
        LL ans = 0;
        for (int u = 1;u <= n;++u) {
            for (int i = G.head[u];i;i = G.G[i].Next) {
                if (G.G[i].w) continue;
                int v = G.G[i].to;
                if (dis[u] == dis[v]) {
                    ans = (ans + dp_s[u] * dp_t[v] % MOD + dp_s[v] * dp_t[u] % MOD) % MOD;
                    G.G[i].w = G.G[i ^ 1].w = 1;
                }
            }
        }
        ans = (ans + dp_s[t]) % MOD;
        printf("%I64d\n", ans);
    }
    return 0;
}
posted @ 2022-08-31 14:31  AE酱  阅读(39)  评论(0编辑  收藏  举报