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. PHP双向队列

    假定队列的左边为头部,右边为尾部 <?php class myDeque { private $deque=array(); /** *头部进队列 */ public function lPus ...

  2. Python接口测试实战4(下) - 框架完善:用例基类,用例标签,重新运行上次失败用例

    如有任何学习问题,可以添加作者微信:lockingfree 课程目录 Python接口测试实战1(上)- 接口测试理论 Python接口测试实战1(下)- 接口测试工具的使用 Python接口测试实战 ...

  3. Unity Lighting - Choosing a Color Space 选择色彩空间(四)

      Choosing a Color Space 选择色彩空间 In addition to selecting a rendering path, it’s important to choose ...

  4. C#匿名参数(转载too)

    匿名方法是在初始化委托时内联声明的方法. 例如下面这两个例子: 不使用匿名方法的委托: using System; using System.Collections.Generic; using Sy ...

  5. Paper Reading - Deep Captioning with Multimodal Recurrent Neural Networks ( m-RNN ) ( ICLR 2015 ) ★

    Link of the Paper: https://arxiv.org/pdf/1412.6632.pdf Main Points: The authors propose a multimodal ...

  6. 欢迎来怼——第四次Scrum会议

    一.小组信息 队名:欢迎来怼小组成员队长:田继平成员:李圆圆,葛美义,王伟东,姜珊,邵朔,冉华小组照片 二.开会信息 时间:2017/10/16 17:15~17:40,总计25min.地点:东北师范 ...

  7. Hadoop环境搭建01

    根据马士兵老师的Hadoop进行的配置 1.首先列下来需要用到的软件 VirtulBox虚拟机.Centos7系统镜像.xshell.xftp.jdk安装包.hadoop-2.7.0安装包 2.在Vi ...

  8. 寒假c++学习计划

    课程选择 概览 清华大学 C++语言程序设计基础 深入学习 清华大学 C++语言程序设计进阶 (2015年秋) 理由 清华大学郑莉老师的课浅显易懂,很适合我这种小白,再加上学习过c语言理解c++基础并 ...

  9. CodeForces 57C Array 组合计数+逆元

    题目链接: http://codeforces.com/problemset/problem/57/C 题意: 给你一个数n,表示有n个数的序列,每个数范围为[1,n],叫你求所有非降和非升序列的个数 ...

  10. erlang驱动使用mysql-otp

    Magnus Ahltorp的Mysql Driver里面介绍emysql的缺陷: 1. 隔离不够好, 2.不能伸缩 mysql-otp使用1个进程1个mysql连接,隔离得很好.推荐使用. mysq ...