P2505 [HAOI2012]道路

题目描述

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

输入输出格式

输入格式:

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

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

输出格式:

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

说明

30%的数据满足:n≤15、m≤30

60%的数据满足:n≤300、m≤1000

100%的数据满足:n≤1500、m≤5000、w≤10000


题目有两点要说。

一、所有点都能作为起点和终点的最短路-->暴力枚举起点

二、统计确定起点任意终点的最短路上的边出现次数

把问题拆分,找到在这些最短路上的边 和 统计边的出现次数

首先考虑找到最短路上的边和边的两端构成的集合最短路图

用到两个比较显然的结论:

1.最短路径上的任意一条边都在最短路图上

2.权值都为正的图的最短路图一定不存在环(当有权为0的边就可能存在环了,比如NOIp2017逛公园

我们可以先跑出最短路,然后枚举边\(E(u,v)\),当\(dis[v]==dis[u]+edge[E(u,v)]\)时,边\(E\)就在最短路图上

关于统计,因为权值都为正无环,所以我们对最短路图考虑topo排序一波

对一条边\(E(u,v)\),如果有\(cnt1\)条路径到\(u\),从\(v\)出去又可以分出\(cnt2\)条路径,则这条边的答案就是\(cnt1*cnt2\)

对于\(cnt1\),其实就是单源的最短路计数。对于\(cnt2\),可以考虑反向建边跑,注意每个点都是起点,所以所有的\(cnt2\)初值都为1

关于卡常:正反图不要嫌麻烦,尽量不要建在一起然后分奇偶边,会T飞的


Code:

#include <cstdio>
#include <cstring>
#include <queue>
#include <iostream>
#define P pair <int ,int>
#define mod 1000000007
#define rg register
using namespace std;
const int N=1502;
const int M=10010;
int head[N],to[M],edge[M],Next[M],is[M],cnt=1,n,m;
inline void add(int u,int v,int w)//i&1 反向边
{
to[++cnt]=v;edge[cnt]=w;Next[cnt]=head[u];head[u]=cnt;
to[++cnt]=u;edge[cnt]=w;Next[cnt]=head[v];head[v]=cnt;
}
void init()
{
scanf("%d%d",&n,&m);
int u,v,w;
for(rg int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
}
P p;int used[N],dis[N],ans[M];
inline void disj(int s)
{
priority_queue <P,vector <P>,greater <P> > q;
memset(used,0,sizeof(used));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
p.first=0,p.second=s;
q.push(p);
while(!q.empty())
{
int u=q.top().second;
q.pop();
if(used[u]) continue;
used[u]=1;
for(int i=head[u];i;i=Next[i])
{
if(i&1) continue;
int v=to[i],w=edge[i];
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
p.first=dis[v],p.second=v;
q.push(p);
}
}
}
}
int in1[N],in2[N],cnt1[N],cnt2[N];
inline void New()
{
memset(is,0,sizeof(is));
memset(in1,0,sizeof(in1));
memset(in2,0,sizeof(in2));
for(rg int u=1;u<=n;u++)
for(int i=head[u];i;i=Next[i])
{
if(i&1) continue;
int v=to[i],w=edge[i];
if(dis[u]+w==dis[v]) is[i]=is[i^1]=1,in1[v]++,in2[u]++;
}
}
inline void topo(int s)
{
memset(cnt1,0,sizeof(cnt1));
memset(cnt2,0,sizeof(cnt2));
queue <int > q;
q.push(s);
cnt1[s]=1;
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=Next[i])
{
if(!is[i]||(i&1)) continue;
int v=to[i];
in1[v]--;
(cnt1[v]+=cnt1[u])%=mod;
if(!in1[v]) q.push(v);
}
}
for(rg int i=1;i<=n;i++)
if(!in2[i])
{
cnt2[i]=1;
q.push(i);
}
while(!q.empty())
{
int u=q.front();
q.pop();
for(int i=head[u];i;i=Next[i])
{
if(!is[i]||!(i&1)) continue;
int v=to[i];
in2[v]--;
(cnt2[v]+=cnt2[u])%=mod;
if(!in2[v]) cnt2[v]++,q.push(v);
}
}
}
inline void cal()
{
for(rg int u=1;u<=n;u++)
for(int i=head[u];i;i=Next[i])
{
if((i&1)||!is[i]) continue;
int v=to[i];
ans[i>>1]=(ans[i>>1]+cnt1[u]*cnt2[v]%mod)%mod;
}
}
void work()
{
for(rg int i=1;i<=n;i++)
{
disj(i);
New();
topo(i);
cal();
}
for(rg int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}
int main()
{
init();
work();
return 0;
}

2018.7.15

洛谷 P2505 [HAOI2012]道路 解题报告的更多相关文章

  1. 洛谷 P1272 重建道路 解题报告

    P1272 重建道路 题目描述 一场可怕的地震后,人们用\(N\)个牲口棚\((1≤N≤150\),编号\(1..N\))重建了农夫\(John\)的牧场.由于人们没有时间建设多余的道路,所以现在从一 ...

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

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

  3. 洛谷 P1783 海滩防御 解题报告

    P1783 海滩防御 题目描述 WLP同学最近迷上了一款网络联机对战游戏(终于知道为毛JOHNKRAM每天刷洛谷效率那么低了),但是他却为了这个游戏很苦恼,因为他在海边的造船厂和仓库总是被敌方派人偷袭 ...

  4. 洛谷 P4597 序列sequence 解题报告

    P4597 序列sequence 题目背景 原题\(\tt{cf13c}\)数据加强版 题目描述 给定一个序列,每次操作可以把某个数\(+1\)或\(-1\).要求把序列变成非降数列.而且要求修改后的 ...

  5. 洛谷1087 FBI树 解题报告

    洛谷1087 FBI树 本题地址:http://www.luogu.org/problem/show?pid=1087 题目描述 我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全 ...

  6. 洛谷 P3313 [SDOI2014]旅行 解题报告

    P3313 [SDOI2014]旅行 题目描述 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教 ...

  7. 洛谷 P3629 [APIO2010]巡逻 解题报告

    P3629 [APIO2010]巡逻 题目描述 在一个地区中有 n 个村庄,编号为 1, 2, ..., n.有 n – 1 条道路连接着这些村 庄,每条道路刚好连接两个村庄,从任何一个村庄,都可以通 ...

  8. 洛谷 P1850 换教室 解题报告

    P1850 换教室 题目描述 对于刚上大学的牛牛来说,他面临的第一个问题是如何根据实际情况申请合适的课程. 在可以选择的课程中,有\(2n\)节课程安排在\(n\)个时间段上.在第\(i(1≤i≤n) ...

  9. 洛谷 P1363 幻想迷宫 解题报告

    P1363 幻想迷宫 题目描述 背景 Background (喵星人LHX和WD同心协力击退了汪星人的入侵,不幸的是,汪星人撤退之前给它们制造了一片幻象迷宫.) WD:呜呜,肿么办啊-- LHX:mo ...

随机推荐

  1. JVM知识(上)

    目录 什么是JVM? JVM的生命周期 JVM的体系结构 JVM的数据类型 java虚拟机被称为"虚拟",因为它是一个抽象的计算机定义的规范.要运行一个Java程序,需要一个抽象的 ...

  2. Selenium2+python自动化-环境搭建

    一.selenium简介 Selenium 是用于测试 Web 应用程序用户界面 (UI) 的常用框架.它是一款用于运行端到端功能测试的超强工具.您可以使用多个编程语言编写测试,并且 Selenium ...

  3. Python爬虫下载Bilibili番剧弹幕

    本文绍如何利用python爬虫下载bilibili番剧弹幕. 准备: python3环境 需要安装BeautifulSoup,selenium包 phantomjs 原理: 通过aid下载bilibi ...

  4. mac 安装配置使用nexus3.x

    一.nexus安装 前置条件 :已经安装了JDK 1:下载nexus(http://www.sonatype.com/download-oss-sonatype) 最新版本3.0,下载目录为/User ...

  5. sqoop 常用命令集

    sqoop是一个介于分布式数据系统与关系型系统之间数据转换的一个数据转换工具 常用命令集sqoop2中sqoop-shell 创建link.job sqoop:001> show link 显示 ...

  6. loadrunner--基础2

    LR11-03 一.并发测试(n VU) 1.并发测试两个条件 1)脚本中要有 集合点(并发点) 2)控制台中要设置并发策略(选择第一项,所有虚拟用户到达集合点后释放) 集合点: 5个线程,代表5个V ...

  7. 常用的不易记忆的css自定义代码

    在制作页面时,经常会遇到需要自定义一些标签的默认行为(如:input的占位符等),但这些默认的设置的css一般比较难记住,所以有必要自己做一下记录.下面是我经常用到的一些重设默认行为的css. 1.占 ...

  8. 作业 20181120-3 Beta发布

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2408 小组介绍 组长:付佳 组员:张俊余 李文涛 孙赛佳 田良 于洋 段 ...

  9. Beta发布——美工+文案

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2408项目地址:https://coding.net/u/wuyy694/ ...

  10. Java 更改日期格式

    import java.util.*; import java.text.*; public class TestDateFormat { public static void main(String ...