luogu2505

luogu2505 [HAOI2012]道路

1 题目描述

C国有n座城市,城市之间通过m条[b]单向[/b]道路连接。一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小。两条最短路不同,当且仅当它们包含的道路序列不同。我们需要对每条道路的重要性进行评估,评估方式为计算有多少条不同的最短路经过该道路。现在,这个任务交给了你。

2 数据范围

100%的数据满足:n≤1500、m≤5000、w≤10000。

3 思路

如果我们确定一个起点,那么可以根据单源最短路径构造出一个有向图无环图(一定是无环的,为什么)。然后如果没有出现这个DAG里面的边,是不可能出现在起点到这些点的最短路径上的。所以我们只要考虑这个DAG上的边就可以了。 做两次拓扑,第一次从起点开始,\(num1[i]\)表示从起点到i有几种走法。第二次逆向拓扑,\(num2[i]\)表示从其他点倒走到i有几种可能性。 那么一条边(x,y)作为最短路径上的边的可能性就是\(num1[x]*num2[y]\)

总的时间复杂度:\(O(nm)\),这里用spfa来求解单源最短路径,没有菊花图,时间效率还挺高的。也可以用堆优化的dijkstra来做,这样时间复杂度就是\(O(n\times mlog n)\)

4 代码

#include<bits/stdc++.h>
using namespace std; 
int const N=1500+3;  
int const M=5000+3;  
int const mod=1e9+7;  
int const inf=1e9;  
struct edge{
	int to,nt,w,id;  
}e[M],e2[M],e3[M]; 
int n,m,h[N],cnt,num1[N],num2[N],ans[M],q[N*N],vis[N],d[N],h2[N],cnt2,ind[N],cnt3,h3[N];  
void add(int a,int b,int c,int d){
	e[++cnt].to=b;  
	e[cnt].nt=h[a];  
	e[cnt].w=c;  
	e[cnt].id=d;  
	h[a]=cnt; 
}
void add2(int a,int b,int c,int d){
	e2[++cnt2].to=b;  
	e2[cnt2].nt=h2[a]; 
	e2[cnt2].w=c;  
	e2[cnt2].id=d;  
	h2[a]=cnt2;  
} 
void add3(int a,int b,int c,int d){
	e3[++cnt3].to=b;  
	e3[cnt3].nt=h3[a];  
	e3[cnt3].w=c; 
	e3[cnt3].id=d;  
	h3[a]=cnt3;  
}
void topology_sort(int s){
	memset(num1,0,sizeof(num1));  
	memset(num2,0,sizeof(num2)); 
	cnt3=0;  
	memset(h3,0,sizeof(h3));  
	int l=0,r=0;q[0]=s; num1[s]=1; 
	while (l<=r){
		int x=q[l++];  
		for(int i=h2[x];i;i=e2[i].nt){
			int v=e2[i].to;  
			ind[v]--;  
			num1[v]=(num1[v]+num1[x])%mod;  
			add3(v,x,e2[i].w,e2[i].id);   
			if(ind[v]==0) 
				q[++r]=v; 
		}
	}
	memset(ind,0,sizeof(ind));  
	for(int i=1;i<=n;i++) 
		for(int j=h3[i];j;j=e3[j].nt){
			int v=e3[j].to;  
			ind[v]++;  
		}
	l=0,r=-1;  
	for(int i=1;i<=n;i++) 
		if(ind[i]==0) q[++r]=i;  
	for(int i=1;i<=n;i++) num2[i]=1;  
	while (l<=r) {
		int x=q[l++];  
		for(int i=h3[x];i;i=e3[i].nt){
			int v=e3[i].to;  
			ind[v]--;  
			num2[v]=(num2[v]+num2[x])%mod;  
			if(ind[v]==0)
				q[++r]=v; 
		}
	}
	for(int i=1;i<=n;i++) 
		for(int j=h2[i];j;j=e2[j].nt){
			int v=e2[j].to;  
			ans[e2[j].id]=(ans[e2[j].id]+1LL*num1[i]*num2[v])%mod;  
		}
}
	
				
void solve(int s){
	memset(vis,0,sizeof(vis));  
	for(int i=1;i<=n;i++) d[i]=inf;
	d[s]=0; 
	int l=0,r=0; 
	q[0]=s; 
	vis[s]=1;  
	while (l<=r){
		int x=q[l++];  
		vis[x]=0;  
		for(int i=h[x];i;i=e[i].nt){
			int v=e[i].to;  
			if(d[v]>d[x]+e[i].w){
				d[v]=d[x]+e[i].w;  
				if(!vis[v]){
					vis[v]=1;  
					q[++r]=v; 
				}
			}
		}
	}
	cnt2=0;  
	memset(h2,0,sizeof(h2));  
	memset(ind,0,sizeof(ind));  
	for(int i=1;i<=n;i++)  
		for(int j=h[i];j;j=e[j].nt){
			int v=e[j].to;   
			if(d[v]==d[i]+e[j].w)  
				add2(i,v,e[j].w,e[j].id),ind[v]++;  
		}
	topology_sort(s); 
}
int main(){
	scanf("%d%d",&n,&m); 
	for(int i=1;i<=m;i++){
		int x,y,z;  
		scanf("%d%d%d",&x,&y,&z);  
		add(x,y,z,i); 
	}
	for(int i=1;i<=n;i++)  
		solve(i);  
	for(int i=1;i<=m;i++)  
		printf("%d\n",ans[i]); 
	return 0; 
}
posted @ 2020-08-13 11:04  zjxxcn  阅读(124)  评论(0编辑  收藏  举报