题解 [HAOI2012]道路
题目大意
给出一个 \(n\) 个点 \(m\) 条边的有向图,问每一条边在多少个最短路径中出现。
\(n\le 1500,m\le 5000\)
思路
算我孤陋寡闻了。。。
很显然,我们需要枚举一个起点 \(s\),然后跑一遍最短路,对于一条边 \((u,v,w)\),如果存在 \(\text{dist}(u)+w=\text{dist}(v)\),可以想到 \((u,v)\) 一定会产生答案,我们定义此类边叫做“最短路径图上的边”,它们构成的图叫做“最短路径图”。它有以下两个性质:
\(u\to v\) 的最短路径上的子路径 \(a\to b\) 也是最短路径
最短路径图上不存在环
证明:
因为如果有环的话与最短路径图上的边的定义矛盾了,所以显然。
然后根据性质1我们就可以观察到我们可以在这个图上做 topo 排序,求出到 \(u\) 的最短路径数,\(v\) 到其它点的最短路径数,相乘即是答案。
时间复杂度 \(\Theta(VE)\),但是用 SPFA 的话还是可以跑很快的。
\(\texttt{Code}\)
#include <bits/stdc++.h>
using namespace std;
#define Int register int
#define mod 1000000007
#define MAXN 5005
template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
bool vis[MAXN],ins[MAXN];
int n,m,toop,st[MAXN],to[MAXN],wei[MAXN],nxt[MAXN],head[MAXN],dist[MAXN];
void Add_Edge (int u,int v,int w){
	to[++ toop] = v,st[toop] = u,wei[toop] = w,nxt[toop] = head[u],head[u] = toop;
}
void SPFA (int s){
	queue <int> q;
	while (!q.empty()) q.pop ();
	memset (vis,0,sizeof (vis));
	memset (dist,0x7f,sizeof (dist));
	dist[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;i = nxt[i]){
			int v = to[i],w = wei[i];
			if (dist[v] > dist[u] + w){
				dist[v] = dist[u] + w;
				if (!vis[v]) vis[v] = 1,q.push (v);
			}
		}
	}
	for (Int i = 1;i <= m;++ i) if (dist[to[i]] == dist[st[i]] + wei[i]) ins[i] = 1;else ins[i] = 0;
}
int que[MAXN],deg[MAXN],ans[MAXN],cnt1[MAXN],cnt2[MAXN];
void Topo (int S){
	memset (deg,0,sizeof (deg));
	memset (cnt1,0,sizeof (cnt1));
	memset (cnt2,0,sizeof (cnt2));
	int tot = 0;cnt1[S] = 1;
	for (Int i = 1;i <= m;++ i) if (ins[i]) deg[to[i]] ++;
	queue <int> q;while (!q.empty()) q.pop();q.push (S);
	while (!q.empty()){
		int u = q.front();q.pop (),que[++ tot] = u;
		for (Int i = head[u];i;i = nxt[i]){
			if (!ins[i]) continue;
			(cnt1[to[i]] += cnt1[u]) %= mod;
			if (!(-- deg[to[i]])) q.push (to[i]);
		}
	}
	for (Int k = tot;k >= 1;-- k){
		int u = que[k];cnt2[u] ++;
		for (Int i = head[u];i;i = nxt[i]){
			if (!ins[i]) continue;
			(cnt2[u] += cnt2[to[i]]) %= mod;
		}
	}
}
void Solve (int S){
	SPFA (S),Topo (S);
	for (Int i = 1;i <= m;++ i) if (ins[i]) (ans[i] += 1ll * cnt1[st[i]] * cnt2[to[i]] % mod) %= mod;
}
signed main(){
	read (n,m);
	for (Int i = 1,u,v,w;i <= m;++ i) read (u,v,w),Add_Edge (u,v,w);
	for (Int S = 1;S <= n;++ S) Solve (S);
	for (Int i = 1;i <= m;++ i) write (ans[i]),putchar ('\n');
	return 0;
}
												
											题解 [HAOI2012]道路的更多相关文章
- 洛谷  P2505 [HAOI2012]道路 解题报告
		
P2505 [HAOI2012]道路 题目描述 C国有n座城市,城市之间通过m条单向道路连接.一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它 ...
 - JZYZOJ1525 HAOI2012道路 堆优化的dijkstra+pair
		
From Tyvj Guest ☆[haoi2012]道路 描述 Description C国有n座城市,城市之间通过m条单向道路连接.一条路径被称为最短路,当 ...
 - 题解 [APIO2013]道路费用
		
link Description 幸福国度可以用 N 个城镇(用 1 到 N 编号)构成的集合来描述,这些城镇 最开始由 M 条双向道路(用 1 到 M 编号)连接.城镇 1 是中央城镇.保证一个 人 ...
 - [HAOI2012]道路
		
题目描述 C国有n座城市,城市之间通过m条[b]单向[/b]道路连接.一条路径被称为最短路,当且仅当不存在从 它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它们包含的道路序列不同. ...
 - [HAOI2012]道路(最短路DAG上计数)
		
C国有n座城市,城市之间通过m条[b]单向[/b]道路连接.一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它们包含的道路序列不同.我们需要对每 ...
 - 洛谷P2505 [HAOI2012]道路(最短路计数)
		
传送门 早上模拟赛考这题,结果竟然看错题目了orz 然后下午看完题解自己做的时候空间开小了白WA了好久orz 首先,如果以$S$为起点,一条边$(u,v)$在最短路上,则$dis[u]+edge[i] ...
 - 洛谷P2505||bzoj2750 [HAOI2012]道路 && zkw线段树
		
https://www.luogu.org/problemnew/show/P2505 https://www.lydsy.com/JudgeOnline/problem.php?id=2750 神奇 ...
 - P2505 [HAOI2012]道路
		
传送门 统计每条边被最短路经过几次,点数不大,考虑计算以每个点为起点时对其他边的贡献 对于某个点 $S$ 为起点的贡献,首先跑一遍最短路,建出最短路的 $DAG$ 考虑 $DAG$ 上的某条边被以 $ ...
 - # HNOI2012 ~ HNOI2018 题解
		
HNOI2012 题解 [HNOI2012]永无乡 Tag:线段树合并.启发式合并 联通块合并问题. 属于\(easy\)题,直接线段树合并 或 启发式合并即可. [HNOI2012]排队 Tag:组 ...
 
随机推荐
- Dockerfile 实践及梳理
			
Dockerfile 是一个文本文件,我们可以通过组合一条条的指令 (Instruction),来构建满足我们需求的 Docker 镜像 文档 Best practices for writing D ...
 - asp获取当前页面url
			
<%Function GetLocationURL() Dim Url Dim ServerPort,ServerName,ScriptName,QueryString ServerName = ...
 - Linux中MySQL的安装以及卸载
			
一.MySQL MySQL是一种开放源代码的关系型数据库管理系统,开发者为瑞典MySQL AB公司.在2008年1月16号被Sun公司收购.而2009年,SUN又被Oracle收购.目前 MySQL被 ...
 - 为什么Class实例可以不是全局唯一的——自定义类加载器
			
为什么Class实例可以不是全局唯一的 通过定义两个类加载器加载同一字节码文件来证明Class实例为什么不是全局唯一的 1.将一个名为Demo(没有后缀)的字节码文件放在D盘根目录 2.定义两个类加载 ...
 - 性能测试工具JMeter 基础(三)—— 创建测试计划
			
如何创建一个完整的测试计划? 安装好JMeter后,通过根目录下的bin目录中的jmeter.bat启动JMeter 添加线程组(Thread Group) 在 Test Plan 鼠标右键 Add- ...
 - Linux环境搭建及项目部署
			
一. VMWare安装图解 1.点击下一步 2.接受条款,下一步 3.选择安装目录,不建议有中文目录和空格目录.下一步 4.下一步 5.这两个选项根据可以爱好习惯选择,下一步 6.安装 7.完成 9. ...
 - 注解@Component方式代替xml装配bean
			
一.@Component 用注解来装配bean 1. 2.对类使用注解,装配bean: 3.类中,注入其他对象: 二.bean.xml中配置@Componet方式装配bean 1.开启注解装配bean ...
 - npm 设置同时从多个包源加载包的方法
			
随着前后端分离技术的发展成熟,越来越来越多的后台系统甚至前端系统采用前后端分离方式,在大型前后端分离系统中,前端往往包含大量的第三方js 包的引用,各个第三方包又可能依赖另外一个第三方包,因此急需要一 ...
 - sticky -- position定位属性sticky值之粘性定位;
			
sticky简述 sticky 是css定为新增的属性:可以说是相对定位relative和固定定位fixed的结合: 它主要用在对scroll事件的监听上,简单说在滑动过程中,某个元素的距离其父元素的 ...
 - Django学习day10随堂笔记
			
每日测验 """ 今日考题 1.默写ajax基本语法,及提交json数据和文件都需要添加哪些额外参数 2.什么是序列化,截止目前为止你所接触过的序列化有哪些 3.批量插入 ...