zoukankan      html  css  js  c++  java
  • P2505 [HAOI2012]道路 最短路树+拓扑排序

    题意:

    给定一张(n)个点,(m)条边的有向图,求每条边被多少最短路经过

    范围&性质:(1le nle 1500,1le mle 5000)

    分析:

    枚举起点,对于每一个起点,建一颗最短路径树(准确来说是一个DAG),然后枚举边计算贡献,由乘法原理得,一个边会被(cnt1[frm] imes cnt2[to])条路径经过,其中(cnt1[frm])表示起点到这条边的发出点的方案数,(cnt2[to])表示终点到这条边结束点的方案数,方案数可以拓扑排序求得顺序求(cnt1),记一下拓扑序后反向求(cnt2),总的复杂度为(O(nmlog_m))

    代码:

    #include<bits/stdc++.h>
    #define pii pair<int,int>
    #define mk(x,y) make_pair(x,y)
    using namespace std;
    
    namespace zzc
    {
    	const int mod =1e9+7;
    	const int maxn = 1e5+5;
    	int n,m,ecnt=0,gcnt=0;
    	int head[maxn],siz[maxn];
    	long long ans[maxn],dis[maxn];
    	bool ins[maxn],vis[maxn];
    	
    	struct edge
    	{
    		int frm,to,nxt,dis;
    	}e[maxn];
    	
    	void add(int u,int v,int w)
    	{
    		e[++ecnt].to=v;
    		e[ecnt].dis=w;
    		e[ecnt].frm=u;
    		e[ecnt].nxt=head[u];
    		head[u]=ecnt;
    	}
    	
    	void dijkstra(int st)
    	{
    		memset(dis,0x7f,sizeof(dis));
    		memset(ins,false,sizeof(ins));
    		memset(vis,false,sizeof(vis));
    		priority_queue<pii> p;
    		p.push(mk(0,st));
    		dis[st]=0;
    		while(!p.empty())
    		{
    			int u=p.top().second;p.pop();
    			if(vis[u]) continue;
    			vis[u]=true;
    			for(int i=head[u];i;i=e[i].nxt)
    			{
    				int v=e[i].to;
    				if(vis[v]) continue;
    				if(dis[v]>dis[u]+e[i].dis)
    				{
    					dis[v]=dis[u]+e[i].dis;
    					p.push(mk(-dis[v],v));
    				}
    			}
    		}
    		for(int i=1;i<=m;i++)
    		{
    			if(dis[e[i].frm]+e[i].dis==dis[e[i].to]) ins[i]=true;
    		}
    	}
    	
    	int rd[maxn],cnt1[maxn],cnt2[maxn],num[maxn],tot;
    	void topo(int st)
    	{
    		memset(rd,0,sizeof(rd));
    		memset(cnt1,0,sizeof(cnt1));
    		memset(cnt2,0,sizeof(cnt2));
    		queue<int> q;
    		q.push(st);
    		cnt1[st]=1;tot=0;
    		for(int i=1;i<=m;i++) if(ins[i]) rd[e[i].to]++;
    		while(!q.empty())
    		{
    			int u=q.front();q.pop();
    			num[++tot]=u;
    			for(int i=head[u];i;i=e[i].nxt)
    			{
    				if(!ins[i]) continue;
    				int v=e[i].to;
    				cnt1[v]=(cnt1[v]+cnt1[u])%mod;
    				if(!(--rd[v])) q.push(v);
    			}
    		}
    		for(int i=tot;i;i--)
    		{
    			int u=num[i];
    			cnt2[u]++;
    			for(int j=head[u];j;j=e[j].nxt)
    			{
    				if(!ins[j]) continue;
    				int v=e[j].to;
    				cnt2[u]=(cnt2[u]+cnt2[v])%mod;
    			}
    		}
    	}
    	
    	void calc(int st)
    	{
    		dijkstra(st);
    		topo(st);
    		for(int i=1;i<=m;i++)
    		{
    			if(!ins[i]) continue;
    		    ans[i]=(ans[i]+1ll*cnt1[e[i].frm]*cnt2[e[i].to]%mod)%mod;	
    		}
    	}
    	
    	void work()
    	{
    		int a,b,c;
    		scanf("%d%d",&n,&m);
    		for(int i=1;i<=m;i++)
    		{
    			scanf("%d%d%d",&a,&b,&c);
    			add(a,b,c);
    		}
    		for(int i=1;i<=n;i++) calc(i);
    		for(int i=1;i<=m;i++) printf("%d
    ",ans[i]);
    	}
    	
    }
    
    int main()
    {
    	zzc::work();
    	return 0;
     } 
    
  • 相关阅读:
    Linux统计文件个数
    python string与list互转
    Python中请使用isinstance()判断变量类型
    xpath提取多个标签下的text
    内存盘
    Watchdog
    渗透测试
    GMT与UTC简介
    ASN.1(抽象语法标记)
    Linux nmap
  • 原文地址:https://www.cnblogs.com/youth518/p/13694587.html
Copyright © 2011-2022 走看看