洛谷传送门
【题目分析】
线段树?bczd,这么小的范围直接暴力就行啦。
直接O(n)枚举源点,每次跑最短路,然后对于每一条路径统计是否在最短路上、两个端点各有多少条最短路径经过即可。
【代码~】
#include<bits/stdc++.h>
using namespace std;
const int MAXN=1e3+510;
const int MAXM=1e4+10;
const int INF=0x3f3f3f3f;
const int MOD=1e9+7;
int n,m,cnt;
int head[MAXN],dis[MAXN],vis[MAXN];
int nxt[MAXM],from[MAXM],to[MAXM],w[MAXM];
int dp1[MAXN],dp2[MAXN];
int du[MAXN];
int ans[MAXM];
int Read(){
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
void add(int x,int y,int z){
nxt[cnt]=head[x];
head[x]=cnt;
from[cnt]=x;
to[cnt]=y;
w[cnt]=z;
cnt++;
}
void SPFA(int s){
queue<int> q;
memset(dis,INF,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(du,0,sizeof(du));
memset(dp1,0,sizeof(dp1));
memset(dp2,0,sizeof(dp2));
dis[s]=0;
vis[s]=1;
q.push(s);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i];
if(dis[v]>dis[u]+w[i]){
dis[v]=dis[u]+w[i];
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
for(int i=0;i<cnt;++i){
int u=from[i],v=to[i];
if(dis[v]==dis[u]+w[i]){
du[v]++;
}
}
}
void bfs(int s){
queue<int> q;
q.push(s);
dp1[s]=1;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i];
if(dis[v]==dis[u]+w[i]){
dp1[v]=(dp1[v]+dp1[u])%MOD;
if(!--du[v]){
q.push(v);
}
}
}
}
}
int dfs(int u){
if(dp2[u])
return dp2[u];
dp2[u]=1;
for(int i=head[u];i!=-1;i=nxt[i]){
int v=to[i];
if(dis[v]==dis[u]+w[i]){
dp2[u]=(dp2[u]+dfs(v))%MOD;
}
}
return dp2[u];
}
int main(){
memset(head,-1,sizeof(head));
n=Read(),m=Read();
for(int i=1;i<=m;++i){
int x=Read(),y=Read(),z=Read();
add(x,y,z);
}
for(int i=1;i<=n;++i){
SPFA(i);
bfs(i);
dfs(i);
for(int j=0;j<cnt;++j){
int u=from[j],v=to[j];
if(dis[u]+w[j]==dis[v]){
ans[j]=(ans[j]+(long long)(dp1[u]*dp2[v])%MOD)%MOD;
}
}
}
for(int i=0;i<cnt;++i)
cout<<ans[i]<<'\n';
return 0;
}