题目链接

题目

题目描述

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

输入描述

第一行包含两个正整数n、m

接下来m行每行包含三个正整数u、v、w,表示有一条从u到v长度为w的道路

输出描述

输出应有m行,第i行包含一个数,代表经过第i条道路的最短路的数目对1000000007取模后的结果

示例1

输入

4 4
1 2 5
2 3 5
3 4 5
1 4 8

输出

2
3
2
1

备注

30% 的数据满足:\(n\leq 15, m\leq 30\) 。

60% 的数据满足:\(n\leq 300, m\leq 1000\) 。

100% 的数据满足:\(n\leq 1500, m\leq 5000, w\leq 10000\) 。

题解

知识点:最短路,计数dp,DAG上dp。

为了求出每条边被最短路经过的次数,我们先以每个点出发考虑。

对于某点 \(i\) 为源点,经过一条边 \(u \to v\) 的最短路条数,可以分解为求 \(u\) 为终点的最短路条数,以及 \(v\) 为起点的最短路条数,最后乘在一起就是以 \(i\) 为源点经过这条边的最短路条数。以下是具体步骤:

  1. 先求出以 \(u\) 为终点的最短路条数,可以通过跑最短路时求出。对于一条边 \(u\to v\) ,若 \(dis[v] > dis[u] + w\) ,则 \(dp[v] = dp[u]\) ;若 \(dis[v] = dis[u] + w\) ,则 \(dp[v] = dp[v] + dp[u]\) 。
  2. 随后求出以 \(v\) 为起点的最短路条数,可以从 \(i\) 自底向上dfs求出,。因为最短路图一定是DAG,所以可以进行DAG上dp。对于某点 \(u\) 的下一个节点 \(v_i\),如果边 $ u \to v_i$ 在最短路上,则先求出以 \(v_i\) 为起点(包括自己为终点,所以初始化 \(dpv[v] = 1\))最短路条数 \(dpv[v_i]\) ,随后可以求出 \(dpv[u] =1+ \sum dpv[v_i]\) ,即以 \(u\) 为起点最短路条数。如果某点以及被计算过了,那就跳过。
  3. 在第二步的同时,我们得到了边 \(u \to v\) 的 \(dp[u]\) 和 \(dpv[v]\) 。那么,这条边以 \(i\) 为源点的答案贡献是 \(dp[u] \cdot dpv[v]\) 。

对每个点都求一遍,累加每条边的贡献即可。

时间复杂度 \(O(n(n+m)\log m)\)

空间复杂度 \(O(n+m)\)

代码

#include <bits/stdc++.h>

using namespace std;

const int mod = 1e9 + 7;
const int N = 1507, M = 5007; struct edge {
int v, nxt, w;
}e[M];
int h[N], idx;
void add(int u, int v, int w) {
e[++idx] = { v,h[u],w };
h[u] = idx;
} bool vis[N];
int dis[N];
int dp[N];///起点到i点的最短路总数
struct node {
int v, w;
friend bool operator<(const node &a, const node &b) {
return a.w > b.w;
}
};
priority_queue<node> pq;
void dijkstra(int s) {
dis[s] = 0;
dp[s] = 1;
pq.push({ s,0 });
while (!pq.empty()) {
int u = pq.top().v;
pq.pop();
if (vis[u]) continue;
vis[u] = 1;
for (int i = h[u];i;i = e[i].nxt) {
int v = e[i].v, w = e[i].w;
if (dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
dp[v] = dp[u];
pq.push(node{ v,dis[v] });
}
else if (dis[v] == dis[u] + w) {
dp[v] = (dp[u] + dp[v]) % mod;
}
}
}
} int dpv[N];///i点把其他点作为终点的最短路总数
int ans[M];
void dfs(int u) {
if (dpv[u]) return;
dpv[u] = 1;///自己作为终点的一种
for (int i = h[u];i;i = e[i].nxt) {
int v = e[i].v, w = e[i].w;
if (dis[v] == dis[u] + w) {
dfs(v);
dpv[u] = (dpv[u] + dpv[v]) % mod;
ans[i] = (ans[i] + 1LL * dp[u] * dpv[v]) % mod;
}
}
} int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
for (int i = 1;i <= m;i++) {
int u, v, w;
cin >> u >> v >> w;
add(u, v, w);
}
for (int i = 1;i <= n;i++) {
for (int j = 1;j <= n;j++) vis[j] = dp[j] = dpv[j] = 0, dis[j] = 0x3f3f3f3f;
dijkstra(i);
dfs(i);
}
for (int i = 1;i <= m;i++) cout << ans[i] << '\n';
return 0;
}

NC19987 [HAOI2012]ROAD的更多相关文章

  1. BZOJ2750: [HAOI2012]Road

    2750: [HAOI2012]Road Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 261  Solved: 113[Submit][Status ...

  2. BZOJ 2750: [HAOI2012]Road( 最短路 )

    对于每个点都跑最短路, 然后我们得到了个DAG, 在这DAG上更新每条边的答案. 考虑e(u, v)∈DAG对答案的贡献:  假设从S到u得路径数为A[u], 从v出发到达任意点的路径数为B[v], ...

  3. [HAOI2012]Road

    2750: [HAOI2012]Road Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 728  Solved: 349[Submit][Status ...

  4. bzoj 2750: [HAOI2012]Road

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

  5. bzoj 2750: [HAOI2012]Road【spfa+dfs】

    枚举起点做spfa,然后一条边在最短路上的条件是dis[e[i].to]==dis[u]+e[i].va,所以每次spfa完之后,dfs出a[i]表示经过i点的最短路的起点数,b[i]表示经过i点的最 ...

  6. 【BZOJ】【2750】【HAOI2012】Road

    最短路+拓扑序DP orz zyf & lyd 统计每条边在多少条最短路径上……其实可以统计 有多少条最短路径经过了x,以及y出发到达任意一个结束点有多少种走法(沿最短路) 我们可以用Dijk ...

  7. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  8. BZOJ2752: [HAOI2012]高速公路(road)

    2752: [HAOI2012]高速公路(road) Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 608  Solved: 199[Submit][ ...

  9. BZOJ 2752: [HAOI2012]高速公路(road)( 线段树 )

    对于询问[L, R], 我们直接考虑每个p(L≤p≤R)的贡献,可以得到 然后化简一下得到 这样就可以很方便地用线段树, 维护一个p, p*vp, p*(p+1)*vp就可以了 ----------- ...

  10. 【线段树】BZOJ2752: [HAOI2012]高速公路(road)

    2752: [HAOI2012]高速公路(road) Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 1621  Solved: 627[Submit] ...

随机推荐

  1. kafka 集群环境搭建

    本文为博主原创,未经允许不得转载: 如果搭建单机节点 kafka 可看我的这篇博客: 搭建 kafka 集群环境,只需要在搭建单机 kafka 环境的基础上,多增加几个kafka 服务实例即可. 多增 ...

  2. The requested URL could not be retrieved

    在开发过程中,调用对外接口,返回了一长串的标签提示,如下 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "ht ...

  3. 使用VS开发人员工具观察类在内存中的布局

    1.先要生成相应文件 2.打开VS2019开发人员工具 3.cd至文件目录 4.输入cl /d1 reportSingleClassLayoutanimal demo.cpp 其中reportSing ...

  4. Go-稀疏数组

    package main import "fmt" // 稀疏数组 // 1. 二维数组 // 2. 存在大量相同相同数据和少量不同数据 // 思维: 将大量相同数据转化为: (数 ...

  5. [转帖]Kafka查看topic、consumer group状态命令

    https://www.cnblogs.com/AcAc-t/p/kafka_topic_consumer_group_command.html 最近工作中遇到需要使用kafka的场景,测试消费程序启 ...

  6. [转帖]使用 goofys 挂载 S3 bucket 为文件系统

    https://xie.infoq.cn/article/7f178e0a1315f758d77c6c2bb 背景 公司的 gitlab 目前都是直接存储在物理盘上,为了确保数据不会丢失,需要重复多次 ...

  7. 隐私集合求交(PSI)协议研究综述

    摘要 隐私集合求交(PSI)是安全多方计算(MPC)中的一种密码学技术,它允许参与计算的双方,在不获取对方额外信息(除交集外的其它信息)的基础上,计算出双方数据的交集.隐私集合求交在数据共享,广告转化 ...

  8. 【JS 逆向百例】网洛者反爬练习平台第六题:JS 加密,环境模拟检测

    关注微信公众号:K哥爬虫,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后 ...

  9. 剪粘板增强小工具(可多次Ctrl+V)

    前言 windows的剪贴板中存储是的最新一次的复制结果,比如先复制A,再复制B,C,在按下粘贴键时粘贴的是最后一次的结果C,在工作时有时候会遇到需要多次复制粘贴的情景,我就在思考有没有一款工具可以保 ...

  10. 从零开始配置vim(21)——lsp简介与treesitter 配置

    截止到上一篇文章,我们配置了neovim的很多内容了.具备了一些编辑器的常用功能了,而且可以胜任日常的文档编辑工作了.但是想作为一个可靠的代码编辑器还缺少重要的一环,即代码语法部分的支持. 在过去的v ...