[HAOI2012]Road


C国有n座城市,城市之间通过m条单向道路连接。一条路径被称为最短路,当且仅当不存在从它的起点到终点的另
外一条路径总长度比它小。两条最短路不同,当且仅当它们包含的道路序列不同。我们需要对每条道路的重要性进
行评估,评估方式为计算有多少条不同的最短路经过该道路。现在,这个任务交给了你。
Input
第一行包含两个正整数n、m
接下来m行每行包含三个正整数u、v、w,表示有一条从u到v长度为w的道路
n≤1500、m≤5000、w≤10000
Output
输出应有m行,第i行包含一个数,代表经过第i条道路的最短路的数目对1000000007取模后的结果
Sample Input
4 4
1 2 5
2 3 5
3 4 5
1 4 8
Sample Output
2
3
2
1

Sol:针对每个点跑一次最短路,然后算出每条边的入度及出度。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define sqr(x) ((x)*(x))
#define lowbit(x) (x&(-x))
#define mid ((l+r)>>1)
#define ls now<<1,l,mid
#define rs now<<1|1,mid+1,r
using namespace std;
const int N=5010,inf=1e9,p=1e9+7;
inline int read()
{
    int x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c<='9'&&c>='0')x=x*10+c-'0',c=getchar();
    return x*f;
}
int head[N],tot,dis[N],u,v,w,n,m,cnt,c[N];
ll a[N],b[N],ans[N];
struct fk
{
    int to,nxt,w;
}e[N];
struct fq
{
    int x,v;
    friend bool operator <(fq a,fq b){return a.v>b.v;}
};
bool in[N];
void add(int u,int v,int w)
{
e[++cnt].to=v;
e[cnt].nxt=head[u];
e[cnt].w=w;
head[u]=cnt;
}
void dijk(int s)
{
    priority_queue<fq> q;
    memset(dis,63,sizeof(dis));
    memset(in,0,sizeof(in));
    q.push((fq){s,0});
	dis[s]=0;tot=0;
    while(!q.empty())
	{
        int x=q.top().x;
		q.pop();
        if(in[x])continue;
        in[x]=1;
		c[++tot]=x;
        for(int i=head[x];i;i=e[i].nxt)
            if(dis[e[i].to]>dis[x]+e[i].w)
                dis[e[i].to]=dis[x]+e[i].w,q.push((fq){e[i].to,dis[e[i].to]}); 
    }
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    a[s]=1;
    for(int i=1;i<=tot;i++)
    	b[c[i]]=1;
    for(int i=1;i<=tot;i++)//取出最短路上的点 
        for(int j=head[c[i]];j;j=e[j].nxt) //j代表从c[i]这个点指出去的边 
            if(dis[c[i]]+e[j].w==dis[e[j].to])
			   a[e[j].to]=(a[e[j].to]+a[c[i]])%p;//算出每个点的入度 
    for(int i=tot;i;i--)
        for(int j=head[c[i]];j;j=e[j].nxt)
            if(dis[c[i]]+e[j].w==dis[e[j].to])
			b[c[i]]=(b[c[i]]+b[e[j].to])%p;//算出点的出度 
    for(int i=1;i<=n;i++)
        for(int j=head[i];j;j=e[j].nxt)
            if(dis[i]+e[j].w==dis[e[j].to])
			ans[j]=(ans[j]+1LL*a[i]*b[e[j].to]%p)%p;
}
int main(){
    n=read();m=read();
    for(int i=1,u,v,w;i<=m;i++)
	u=read(),v=read(),w=read(),add(u,v,w);
    for(int i=1;i<=n;i++)
     	dijk(i);
    for(int i=1;i<=m;i++)
	printf("%lld\n",ans[i]);
}

  

原文地址:https://www.cnblogs.com/cutemush/p/11780217.html