[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=2750
[算法]
考虑计算每个点对每条边的贡献
对于每个点首先运行SPFA或Dijkstra单源最短路 , 建出以该点为根的最短路树(图)
由于最短路图是一个DAG(有向无环图) , 我们可以求出其拓扑序列 , 对于每个点i , 计算 :
CNT1 : 从枚举的点到该点的 , 最短路图上的路径条数
CNT2 : 从该点出发 , 在最短路图上 , 有多少条路径
对于每条在最短路图上的边 , 用乘法原理计算贡献即可
时间复杂度 : O(NM)
[代码]
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; const int N = 5010; const int inf = 2e9; const int P = 1e9 + 7; struct edge { int to , w , nxt; } e[N << 1]; int n , m , tot; int dist[N] , cnta[N] , cntb[N] , u[N] , v[N] , w[N] , head[N] , topo[N] , ans[N]; bool ok[N]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void addedge(int u , int v , int w) { ++tot; e[tot] = (edge){v , w , head[u]}; head[u] = tot; } inline void spfa(int S) { static bool inq[N]; queue< int > q; for (int i = 1; i <= n; ++i) { dist[i] = inf; inq[i] = false; cnta[i] = cntb[i] = 0; } for (int i = 1; i <= m; ++i) ok[i] = false; q.push(S); inq[S] = true; dist[S] = 0; while (!q.empty()) { int cur = q.front(); q.pop(); inq[cur] = false; for (int i = head[cur]; i; i = e[i].nxt) { int v = e[i].to , w = e[i].w; if (dist[cur] + w < dist[v]) { dist[v] = dist[cur] + w; if (!inq[v]) { inq[v] = true; q.push(v); } } } } for (int i = 1; i <= m; ++i) if (dist[u[i]] + w[i] == dist[v[i]]) ok[i] = true; } inline void calc() { queue< int > q; static int deg[N]; for (int i = 1; i <= n; ++i) deg[i] = 0; for (int i = 1; i <= m; ++i) if (ok[i]) ++deg[v[i]]; for (int i = 1; i <= n; i++) if (!deg[i]) { cnta[i] = 1; q.push(i); } int M = 0; while (!q.empty()) { int cur = q.front(); q.pop(); topo[++M] = cur; for (int i = head[cur]; i; i = e[i].nxt) { int v = e[i].to; if (!ok[i]) continue; cnta[v] = (cnta[v] + cnta[cur]) % P; if (!(--deg[v])) q.push(v); } } for (int i = n; i >= 1; i--) { ++cntb[topo[i]]; for (int j = head[topo[i]]; j; j = e[j].nxt) { int v = e[j].to; if (!ok[j]) continue; cntb[topo[i]] = (cntb[topo[i]] + cntb[v]) % P; } } } inline void update(int S) { spfa(S); calc(); for (int i = 1; i <= m; ++i) if (ok[i]) ans[i] = (ans[i] + 1ll * cnta[u[i]] * cntb[v[i]] % P) % P; } int main() { read(n); read(m); for (int i = 1; i <= m; ++i) { read(u[i]); read(v[i]); read(w[i]); addedge(u[i] , v[i] , w[i]); } for (int i = 1; i <= n; ++i) update(i); for (int i = 1; i <= m; ++i) printf("%d " , ans[i]); return 0; }