链接

  • 最短路径\(dag\),一道好题。
  • 题目大意:求一张图中满足下列要求的点对\((i,j)\)数量:
  • 所有最短路径必定会经过 \(i\) 点和 \(j\) 点中的任意一点。
  • 不存在一条最短路同时经过 \(i\) 点和 \(j\) 点。
  • 考虑这两个限制是啥。
  • 首先所有最短路要么经过\(i\)点,要么经过\(j\)点,不存在两个都不经过或者都经过的。
  • 所以经过\(i\)点的最短路方案加上经过\(j\)点的最短路方案不存在交集。
  • 那么考虑怎么求最短路方案,先做一边\(dij\),然后在\(tag\)上\(dp\)方案数即可,正反都做一遍。
  • 那么有\(f_{i,0}\)表示从\(s\)到\(i\)正向最短路方案数,
  • 经过\(i\)点的最短路方案设为\(F_{i}\),有$${F_{i}=f_{i,0}*f_{i,1}}$$
  • 所以满足要求的\(i,j\)可写为:$$F_i+F_j=F_t$$。
  • 这个满足了还不够,因为这个只是\(i,j\)的必要条件,还不是充分条件。
  • 关键在于所有的路径不能同时经过这两个点。
  • 设\(G_{i,0}\)表示从\(s\)点到\(i\)点可能经过的点集,\(bitset\)实现,\(G_{i,1}\)同理。
  • 转移拓扑排序实现即可。
  • 所以我们对于每一个\(i\),想知道\(F_{t}-F_{i}=F_{j}\)中,\(j\)的点数,减去\(i\)可以到达的点数。
  • 维护一个\(map\),记录\(F_{j}\)这个集合中的点。
  • 那么对于一个\(i\),他能产生的贡献就是集合$$S=G_{F_t-F_i}\ and\ G_{i,0}\ and \ G_{i,1}$$
  • 的\(1\)的个数。
  • 空间\(1GB\)就可以过
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define R register int
#define ll long long
using namespace std;
const int N=50001;
const int M=100001;
const ll inf=1e18;
const int mod=1000000009;
int n,m,s,u,v,x,t,ans,vis[N];
int cnt,nt[M],to[M],hd[N],w[M];
int du[N];
ll Dis[2][N],f[2][N],F[N];
void link(R f,R t,R d){nt[++cnt]=hd[f],to[cnt]=t,w[cnt]=x,hd[f]=cnt;}
bitset<50001>G[2][N];
map<ll,bitset<50001> >Ms;
int gi(){
R x=0,k=1;char c=getchar();
while((c<'0'||c>'9')&&c!='-')c=getchar();
if(c=='-')k=-1,c=getchar();
while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
return x*k;
}
struct ip{int id;ll val;};
int operator < (ip x,ip y){return x.val>y.val;}
priority_queue<ip>Q;
void dij(R op){
while(!Q.empty())Q.pop();
for(R i=1;i<=n;++i)vis[i]=0,Dis[op][i]=inf;
if(op)Dis[1][t]=0,Q.push((ip){t,0}),f[op][t]=1;
else Dis[0][s]=0,Q.push((ip){s,0}),f[op][s]=1;
while(!Q.empty()){
ip s=Q.top();Q.pop();
if(vis[s.id])continue;
R i=s.id;vis[i]=1;
for(R k=hd[i];k;k=nt[k]){
if(Dis[op][to[k]]>Dis[op][i]+w[k]){
Dis[op][to[k]]=Dis[op][i]+w[k];
f[op][to[k]]=f[op][i],Q.push((ip){to[k],Dis[op][to[k]]});
}
else if(Dis[op][to[k]]==Dis[op][i]+w[k])
f[op][to[k]]+=f[op][i];
}
}
}
queue<int>til;
void top(R op){
for(R i=1;i<=n;++i)
for(R k=hd[i];k;k=nt[k])
if(Dis[op][i]+w[k]+Dis[!op][to[k]]==Dis[0][t])
du[to[k]]++;
for(R i=1;i<=n;++i){
G[op][i].set(),G[op][i][0]=G[op][i][i]=0;
if(!du[i])til.push(i);
}
while(!til.empty()){
R i=til.front();til.pop();
for(R k=hd[i];k;k=nt[k])
if(Dis[op][i]+w[k]+Dis[!op][to[k]]==Dis[0][t]){
du[to[k]]--,G[op][to[k]]&=G[op][i];
if(!du[k])til.push(to[k]);
}
}
}
int main(){
n=gi(),m=gi(),s=gi(),t=gi();
for(R i=1;i<=m;++i)
u=gi(),v=gi(),x=gi(),link(u,v,x),link(v,u,x);
dij(0),dij(1);
if(!f[0][t])return printf("%lld",1ll*n*(n-1)/2),0;
for(R i=1;i<=n;++i)
if(Dis[0][i]+Dis[1][i]==Dis[0][t])
F[i]=f[0][i]*f[1][i];
top(0),top(1);
for(R i=1;i<=n;++i)Ms[F[i]].set(i);
for(R i=1;i<=n;++i)
ans+=(Ms[F[t]-F[i]]&G[0][i]&G[1][i]).count();
cout<<(ans>>1);
return 0;
}

luogu4061 大吉大利,晚上吃鸡!的更多相关文章

  1. GMA Round 1 大吉大利,晚上吃鸡

    传送门 大吉大利,晚上吃鸡 新年走亲访友能干点啥呢,咱开黑吃鸡吧. 这里有32个人,每个人都可能想玩或者不想玩,这样子一共有$2^{32}$种可能.而要开黑当然得4人4人组一队(四人模式),所以说如果 ...

  2. [BZOJ5109]大吉大利,晚上吃鸡!

    [BZOJ5109]大吉大利,晚上吃鸡! 题目大意: 一张\(n(n\le5\times10^4)\)个点\(m(m\le5\times10^4)\)条边的无向图,节点编号为\(1\)到\(n\),边 ...

  3. 【BZOJ5109】[CodePlus 2017]大吉大利,晚上吃鸡! 最短路+拓扑排序+DP

    [BZOJ5109][CodePlus 2017]大吉大利,晚上吃鸡! Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏 ...

  4. bzoj5109: [CodePlus 2017]大吉大利,晚上吃鸡!

    Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏中,皮皮 和毛毛最喜欢做的事情就是堵桥,每每有一个好时机都能收到不少的快 ...

  5. 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!(dij+bitset)

    从S出发跑dij,从T出发跑dij,顺便最短路计数. 令$F(x)$为$S$到$T$最短路经过$x$的方案数,显然这个是可以用$S$到$x$的方案数乘$T$到$x$的方案数来得到. 然后第一个条件就变 ...

  6. BZOJ5109 CodePlus 2017大吉大利,晚上吃鸡!(最短路+拓扑排序+bitset)

    首先跑正反两遍dij求由起点/终点到某点的最短路条数,这样条件一就转化为f(S,A)*f(T,A)+f(S,B)*f(T,B)=f(S,T).同时建出最短路DAG,这样图中任何一条S到T的路径都是最短 ...

  7. 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!

    n<=50000,m<=50000的图,给s和t,问有多少点对$(a,b)$满足 嗯. 不会. 首先最短路DAG造出来,然后两个条件转述一下:条件一,$N_a$表示从s到t经过a的路径,$ ...

  8. [Code+#1]大吉大利,晚上吃鸡!

    输入输出样例 输入样例#1: 7 7 1 7 1 2 2 2 4 2 4 6 2 6 7 2 1 3 2 3 5 4 5 7 2 输出样例#1: 6 输入样例#2: 5 5 1 4 1 2 1 1 3 ...

  9. [BZOJ5109/CodePlus2017]大吉大利,晚上吃鸡!

    Description 最近<绝地求生:大逃杀>风靡全球,皮皮和毛毛也迷上了这款游戏,他们经常组队玩这款游戏.在游戏中,皮皮和毛毛最喜欢做的事情就是堵桥,每每有一个好时机都能收到不少的快递 ...

随机推荐

  1. vue双向绑定原理(简单实现原理附demo)

    先上效果图 简单的实现数据的双向绑定首先来了解一个东西:Object.defineProperty() https://developer.mozilla.org/zh-CN/docs/Web/Jav ...

  2. js常用的几种类型检测方式

    类型检测方式 平时数据类型都是清晰明了的,但有些功能函数还是需要用到类型检测,现总结一下几种常见的类型检测方式: typeof instanceof Object.prototype.toString ...

  3. 非web工程,打jar放shell执行

    作为6年经验的程序员,一直在搞web服务应用开发,今天领导被吐槽了,只会web方面的东东,最基本的打包啥啥都不会.. 一般开发工程都是web项目,突然要求开发非web,不用tomcat装(浪费端口号) ...

  4. VMware 虚拟化编程(9) — VMware 虚拟机的快照

    目录 目录 前文列表 VMware 虚拟机的快照 快照的执行过程 删除快照 快照类型 Quiseced Snapshot 前文列表 VMware 虚拟化编程(1) - VMDK/VDDK/VixDis ...

  5. 阶段1 语言基础+高级_1-3-Java语言高级_06-File类与IO流_08 转换流_2_编码引出的问题_FileReader读取GBK格式文件

    IDEA默认的编码格式是UTF-8 新建一个txt文件.输入你好 ANSI就是系统默认编码.保存即可. 通过IDE打开是乱码的,因为默认打开的方式是UTF-8 转换为char类型 输出了乱码

  6. #Week 11 - 343.Integer Break

    Week 11 - 343.Integer Break Given a positive integer n, break it into the sum of at least two positi ...

  7. Python笔记(二十七)_魔法方法_容器

    定制容器 容器类型的协议: 定制不可变容器,只需要定义__len__()和__getitem__()方法 定制可变容器,需要定义__len__().__getitem__().__setitem__( ...

  8. spring Cloud 之 Eureka、Feign、Hystrix、Zuul、Config、Bus

    一.服务发现——Netflix Eureka Eureka包含两个组件: Eureka Server和Eureka Client 1.创建Eureka Server服务端 (1).引入依赖 父工程po ...

  9. 防止XSRF 解决方案

    1.首先在表单提交页面生成校验使用的Token public ActionResult Index() { //Token验证需要使用的token string token = System.Guid ...

  10. react-redux --》react中 最好用的状态管理方式

    一.Redux与组件 react-redux是一个第三方插件使我们在react上更方便的来使用redux这个数据架构 React-Redux提供connect方法,用于从UI组件生成容器组件,conn ...