BZOJ 2750: [HAOI2012]Road【最短路】

首先介绍一个概念,最短路图(不是很重要只是方便我叙述)。

我们以 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 xy,设从 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 xy对答案的贡献为 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 xy,显然有递推式 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;
}

你可能感兴趣的:(BZOJ,图论-最短路)