题目传送门

题目大意

给出一个 \(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]道路的更多相关文章

  1. 洛谷 P2505 [HAOI2012]道路 解题报告

    P2505 [HAOI2012]道路 题目描述 C国有n座城市,城市之间通过m条单向道路连接.一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它 ...

  2. JZYZOJ1525 HAOI2012道路 堆优化的dijkstra+pair

    From Tyvj Guest ☆[haoi2012]道路                 描述 Description     C国有n座城市,城市之间通过m条单向道路连接.一条路径被称为最短路,当 ...

  3. 题解 [APIO2013]道路费用

    link Description 幸福国度可以用 N 个城镇(用 1 到 N 编号)构成的集合来描述,这些城镇 最开始由 M 条双向道路(用 1 到 M 编号)连接.城镇 1 是中央城镇.保证一个 人 ...

  4. [HAOI2012]道路

    题目描述 C国有n座城市,城市之间通过m条[b]单向[/b]道路连接.一条路径被称为最短路,当且仅当不存在从 它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它们包含的道路序列不同. ...

  5. [HAOI2012]道路(最短路DAG上计数)

    C国有n座城市,城市之间通过m条[b]单向[/b]道路连接.一条路径被称为最短路,当且仅当不存在从它的起点到终点的另外一条路径总长度比它小.两条最短路不同,当且仅当它们包含的道路序列不同.我们需要对每 ...

  6. 洛谷P2505 [HAOI2012]道路(最短路计数)

    传送门 早上模拟赛考这题,结果竟然看错题目了orz 然后下午看完题解自己做的时候空间开小了白WA了好久orz 首先,如果以$S$为起点,一条边$(u,v)$在最短路上,则$dis[u]+edge[i] ...

  7. 洛谷P2505||bzoj2750 [HAOI2012]道路 && zkw线段树

    https://www.luogu.org/problemnew/show/P2505 https://www.lydsy.com/JudgeOnline/problem.php?id=2750 神奇 ...

  8. P2505 [HAOI2012]道路

    传送门 统计每条边被最短路经过几次,点数不大,考虑计算以每个点为起点时对其他边的贡献 对于某个点 $S$ 为起点的贡献,首先跑一遍最短路,建出最短路的 $DAG$ 考虑 $DAG$ 上的某条边被以 $ ...

  9. # HNOI2012 ~ HNOI2018 题解

    HNOI2012 题解 [HNOI2012]永无乡 Tag:线段树合并.启发式合并 联通块合并问题. 属于\(easy\)题,直接线段树合并 或 启发式合并即可. [HNOI2012]排队 Tag:组 ...

随机推荐

  1. 并发编程之:synchronized

    大家好,我是小黑,一个在互联网苟且偷生的农民工. 之前的文章中跟大家分享了关于Java中线程的一些概念和基本的使用方法,比如如何在Java中启动一个线程,生产者消费者模式等,以及如果要保证并发情况下多 ...

  2. java一些工具类

    import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java. ...

  3. 怎样去除EXCEL中的重复行

    工具/原料 安装了EXCEL2010的电脑一台 步骤/方法   假如我们的表格中有下图所示的一系列数据,可以看出其中有一些重复.   首先我们选中所有数据.可以先用鼠标点击"A1单元格&qu ...

  4. AQS实现原理

    AQS实现原理 AQS中维护了一个volatile int state(共享资源)和一个CLH队列.当state=1时代表当前对象锁已经被占用,其他线程来加锁时则会失败,失败的线程被放入一个FIFO的 ...

  5. uboot常用命令及其使用

    环境变量设置 setenv 设置一个环境变量 # 格式:setenv key vlaue setenv bootdelay 5 # 设置uboot启动延时5s 删除一个环境变量 uboot对于一个没有 ...

  6. kali linux 的基本命令

    Kali Linux 命令集 系统信息 arch 显示机器的处理器架构(1) uname -m 显示机器的处理器架构(2)uname -r 显示正在使用的内核版本dmidecode -q 显示硬件系统 ...

  7. 学了这么多年C语言,你真的知道全局变量,局部变量,静态变量,本地函数,外部函数是如何区分标识的吗?

    动态库内容分析 文章目录 动态库内容分析 1. 动态库编译 1.1 第一个C文件:basic.c 1.2第二个C文件:demo.c 1.3第三个C文件:main.c 2.动态库编译 3.二进制内容分析 ...

  8. eclipes常见操作总结及项目2和3经验总结

    eclipes常见操作总结及项目2经验总结 eclipes提示: 打开eclipes 选择window->perference->java->editor->content a ...

  9. vue开发流程

    在安装node.js 测试安装  在cmd 下输入node   如查能正确输出命令提示符,表明安装好node 测试安装npm -v   如果能成功出现版本信息表示安装好npm 安装配置 G码云   或 ...

  10. CodeForce-799C Fountains (记忆化DP)

    Fountains CodeForces - 799C 某土豪想要造两座喷泉.现在有 n 个造喷泉的方案,我们已知每个方案的价格以及美观度.有两种合法的货币:金币和钻石.这两种货币之间不能以任何方式转 ...