毒瘤题
拓扑+SPFA+暴力枚举
枚举起点,跑SPFA求出dis[i]
然后每进行完一次SPFA,就枚举最短路图中的所有边--->满足dis[fr]+cost=dis[to]的边就是最短路上的边,把这些边标记起来,构成一张最短路图,显然这张图上不存在环,因为不可能存在一条路径满足u->v->z->u,显然我们可以拓扑统计到达每个点的方案数
tot[to]+=tot[fr]
然后我们对于在最短路图中的点,u->v,显然这也是一条最短路径,不然的话,必定存在u->k->v,使得原图的最短路变小,然后我们就需要统计一下每个点出发的最短路,显然从这个点出发的边,并且存在于最短路图上,那这就是一条最短路,所以cnt[fr]+=cnt[to]
最后统计一条边的贡献时,显然根据乘法原理ans[i]=tot[fr]*cnt[to],即到达这条边一个端点的最短路数*从另一个端点出去的最短路数
代码
//By AcerMo
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int M=100500;
const int mod=1e9+7;
int n,m;
int tot[M],all[M],emm[M];
int dis[M],vis[M],ono[M],ans[M];
int to[M],nxt[M],w[M],head[M],fr[M],cnt;
stack<int>s;
inline int read()
{
int x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void add(int x,int y,int z)
{
to[++cnt]=y;fr[cnt]=x;nxt[cnt]=head[x];w[cnt]=z;head[x]=cnt;
return ;
}
inline void SPFA(int st)
{
fill(dis,dis+n+1,2e9);
fill(ono,ono+m+1,0);
queue<int>q;dis[st]=0;q.push(st);
while (q.size())
{
int u=q.front();q.pop();vis[u]=0;
for (int i=head[u];i;i=nxt[i])
if (dis[to[i]]>dis[u]+w[i])
{
dis[to[i]]=dis[u]+w[i];
if (!vis[to[i]])
vis[to[i]]=1,q.push(to[i]);
}
}
for (int i=1;i<=m;i++)
if (dis[fr[i]]+w[i]==dis[to[i]])
ono[i]=1;//确定本次的所有可行路径
return ;
}
inline void topsort(int st)
{
fill(emm,emm+n+1,0);
fill(tot,tot+n+1,0);
fill(all,all+n+1,0);
queue<int>q;tot[st]=1;q.push(st);
for (int i=1;i<=m;i++) emm[to[i]]+=ono[i];//计算入度
while (q.size())
{
int u=q.front();q.pop();s.push(u);
for (int i=head[u];i;i=nxt[i])
if (ono[i])//必须是最短路图中的边
{
if (--emm[to[i]]==0) q.push(to[i]);
tot[to[i]]=(tot[to[i]]+tot[u])%mod;//拓扑统计所有的数量
}
}
while (s.size())
{
int u=s.top();s.pop();all[u]++;
for (int i=head[u];i;i=nxt[i])
if (ono[i])
all[u]=(long long int)(all[u]+all[to[i]])%mod;
}
return ;
}
inline void slove(int st)
{
SPFA(st);topsort(st);
for (int i=1;i<=m;i++)
if (ono[i]) ans[i]=(ans[i]+1LL*tot[fr[i]]*all[to[i]]%mod)%mod;
return ;
}
signed main()
{
n=read();m=read();int x,y,z;
for (int i=1;i<=m;i++)
x=read(),y=read(),z=read(),add(x,y,z);
for (int i=1;i<=n;i++) slove(i);
for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}