首先介绍一个概念,最短路图(不是很重要只是方便我叙述)。
我们以 S S S为起点对图 G G G做一次最短路算法,如果 G G G的子图 G ′ G' G′满足: G ′ G' G′的任意一条边都在某一条最短路径上,且不在 G ′ G' G′的任意一条边都不在任意一条最短路径上,则将 G ′ G' G′称为点 S S S的最短路图。
于是我们可以考虑枚举每个点作为起点,跑最短路。
然后讨论 i i i的最短路图 G G G上的边对于答案的贡献。
对于 G G G上的边 x → y x→y x→y,设从 i i i到 x x x的最短路径有 c n t 1 [ x ] cnt_1[x] cnt1[x]条,经过 y y y且以 y y y为出边的最短路径有 c n t 2 [ y ] cnt_2[y] cnt2[y]条。
显然,根据乘法原理,在 G G G中,边 x → y x→y x→y对答案的贡献为 c n t 1 [ x ] ∗ c n t 2 [ y ] cnt_1[x]*cnt_2[y] cnt1[x]∗cnt2[y]。
于是我们考虑求得 c n t 1 [ ] , c n t 2 [ ] cnt_1[],cnt_2[] cnt1[],cnt2[]。
显然,在最短路图上,不存在环,于是我们先拓扑排序。
对于 G G G上的边 x → y x→y x→y,显然有递推式 c n t 1 [ y ] + = c n t 1 [ x ] cnt_1[y]+=cnt_1[x] cnt1[y]+=cnt1[x],初始化 c n t 1 [ i ] = 1 cnt_1[i]=1 cnt1[i]=1
然后我们考虑拓扑排序的逆序,有递推式 c n t 2 [ x ] + = c n t 2 [ y ] cnt_2[x]+=cnt_2[y] cnt2[x]+=cnt2[y],初始化 c n t 2 [ ] = 1 cnt_2[]=1 cnt2[]=1
#include
#define ll long long
using namespace std;
const ll N=1505;
const ll M=10005;
const ll Inf=1e18;
const ll Mod=1e9+7;
ll ans[M];
ll inc,from[M],to[M],edg[M],nxt[M],head[N];
ll n,m,in[N],dis[N],vis[M],cnt1[N],cnt2[N];
inline ll add(ll x,ll y) {
x+=y;return x>=Mod?x-Mod:x;
}
inline ll mul(ll x,ll y) {
return x*y%Mod;
}
void ins(ll x,ll y,ll z) {
++inc;from[inc]=x;to[inc]=y;edg[inc]=z;nxt[inc]=head[x];head[x]=inc;
}
void spfa(ll s) {
for(ll i=1;i<=n;i++) dis[i]=Inf,vis[i]=0;
queueq;dis[s]=0;vis[s]=1;q.push(s);
while(q.size()) {
ll x=q.front();q.pop();vis[x]=0;
for(ll i=head[x];i;i=nxt[i]) {
ll y=to[i],z=edg[i];
if(dis[y]>dis[x]+z) {
dis[y]=dis[x]+z;
if(!vis[y]) vis[y]=1,q.push(y);
}
}
}
}
void dfs1(ll x) {
vis[x]=1;
for(ll i=head[x];i;i=nxt[i]) {
ll y=to[i],z=edg[i];
if(dis[y]==dis[x]+z) {
in[y]++;
if(!vis[y]) dfs1(y);
}
}
}
void dfs2(ll x) {
for(ll i=head[x];i;i=nxt[i]) {
ll y=to[i],z=edg[i];
if(dis[y]==dis[x]+z) {
vis[i]=1;cnt1[y]=add(cnt1[y],cnt1[x]);
if(--in[y]==0) dfs2(y);
}
}
}
void dfs3(ll x) {
cnt2[x]=1;
for(ll i=head[x];i;i=nxt[i]) {
ll y=to[i],z=edg[i];
if(dis[y]==dis[x]+z) {
if(!cnt2[y]) dfs3(y);
cnt2[x]=add(cnt2[x],cnt2[y]);
}
}
}
int main() {
scanf("%lld%lld",&n,&m);
for(ll i=1;i<=m;i++) {
ll x,y,z;
scanf("%lld%lld%lld",&x,&y,&z);ins(x,y,z);
}
for(ll i=1;i<=n;i++) {
spfa(i);
memset(vis,0,sizeof(vis));dfs1(i);
memset(vis,0,sizeof(vis));
memset(cnt1,0,sizeof(cnt1));
memset(cnt2,0,sizeof(cnt2));cnt1[i]=1;dfs2(i);dfs3(i);
for(ll j=1;j<=m;j++) if(vis[j]) ans[j]=add(ans[j],mul(cnt1[from[j]],cnt2[to[j]]));
}
for(ll i=1;i<=m;i++) printf("%lld\n",ans[i]);
return 0;
}