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. Sublime Text 3安装完美的Vim支持,ActualVim/NeoVim

    很多IDE和编辑器都有Vim插件用于支持Vim模式,但大多数都有些问题,拿我一直用的Idea来说,它的vim在ctrl+v后,选择多行的行前插入,如果这几行中有空行,它不会把空格算在内,所以最终是会少 ...

  2. 获取安卓app的appPackage和appActivity

    1.需要配置好android的开发环境后,打开cmd命令窗口 2.在命令窗口中输入,adb logcat>D:/log.log,抓取日志 3.运行启动app 4.查看日志log 5.搜索日志的关 ...

  3. Django-建立网页

    进入cmd模式做 django-admin startproject helloworld创建一个project,并命名helloworld,新生成的文件结构如下   输入python manage. ...

  4. Cesium开发添加entity无法显示

    无代码报错,js查询entity数量发现确实添加进去了.但是在底图上就是不显示. 有可能是跨域产生的问题.打开开发者工具Console栏.查看是不是存在跨域错误. 解决跨域后entity正常加载.

  5. 城市规模越大,工资、GDP、犯罪率越高:4.5星|《规模》

    规模 信息浓度非常高的一本书.篇幅也不小,纸书有568页,致谢与注释只占7%. 全书讲各种复杂的东西中存在的普遍规律:哺乳动物体重每增加一倍,心率降低25%:城市人口每增加一倍,加油站只增加85%:城 ...

  6. TCP的三次握手(建立连接)和四次挥手(关闭连接)(转)

    转自:(http://www.cnblogs.com/Jessy/p/3535612.html) 参照: http://course.ccniit.com/CSTD/Linux/reference/f ...

  7. java 数据存储

    简单的记录一下而已. 1.寄存器: 特点:快,存储有限. 存储地点:处理器内部. 2.堆栈 特点:仅次于寄存器快,通过堆栈指针在处理器获取支持.堆栈指针下移,分配内存,上移,释放内存.此外须知生命周期 ...

  8. dRMT: Disaggregated Programmable Switching

    dRMT: Disaggregated Programmable Switching 2017年SIGCOMM会议上提出的新型可编程交换机架构,对2013年提出的RMT架构存在的问题进行了优化. 主要 ...

  9. 周总结<6>

    周次 学习时间 新编写代码行数 博客量(篇) 学到知识点 13 10 100 2 网页设计:邻接矩阵深度以及广度遍历

  10. Web.config配置configSections学习

    文章:c# 配置文件之configSections配置 configSections节点需要位于configuration第一的位置,紧挨configuration. <configuratio ...