演艺
演艺
题目描述
一张 N 个点M 条无向边的图,节点编号为 1 到 N,每条边具有一个正整数的长度。
假定黄花敦会从 S点出发到达 T 点,并且只会走最短路,wxh 和 wsq 会在 A 点和 B 点 埋伏黄花敦。
为了保证一定能埋伏到黄花敦,同时 wxh 又想制造单独和黄花敦相处的机会,A 点和 B 点必须满足:黄花敦所有可能路径中,必定会经过 AA 点和 BB 点中的任意一点且不存在一条 路径同时经过 A 点和 B 点。
Wxh 想知道满足上面两个条件的 A,B 点对有多少个,交换 A,B 的顺序算相同的方案。
输入
第一行四个整数 N,M,S,TN,M,S,T ,接下来 MM 行每行三个整数 a,b,wa,b,w 表示有一条连接 aa 和 bb 的长度为 ww 的边。
输出
一行一个整数表示答案
样例输入
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
样例输出
6
提示
【样例解释】
<2,3>,<2,4>,<4,3>,<4,5>,<6,3>,<6,5><2,3>,<2,4>,<4,3>,<4,5>,<6,3>,<6,5>
【数据范围和约定】
1≤n≤5×104,1≤m≤5×104,1≤w≤109
solution
首先跑出最短路网。
要求的是AB在最所有短路上并且不能有一条路既过A,又过B。
用dp求出与过每一个点的最短路数。离散化,用bitset记某一种最短路对应着哪些点。
那么这时如果有两个点的最短路的条数和等于总的最短路数,并且他么的最短路没有重合,那就是合法的(A.B)
再用另一个 bitset 把与每一个点连接的点求出来。
这里的连接指同在某一条最短路。
假设我现在要算x的答案
假设x的最短路数为A ,总最短路数为num
最短路数为n-A的点集记为S
与x相连的点集为T
x的答案为S^(S&T)
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<bitset>
#include<queue>
#include<map>
#define maxn 50005
#define inf 1e18
#define ll long long
using namespace std;
int n,m,S,T,head[maxn],tot,in[2][maxn];
int flag[maxn],HEAD[maxn],tot2,top,cnt,sz;
ll d[2][maxn],a[maxn],w[maxn],f[2][maxn],dy[maxn],ans;
map<ll,int>ls;
struct node{
ll w;int v,nex;
}e[maxn*2],e2[maxn*2];
struct Node{
int x;ll dist;
bool operator <(const Node &T)const{
return T.dist<dist;
}
};
bitset<maxn>fl[2][maxn],fs[maxn],now;
void lj(int t1,int t2,ll t3){
e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1];head[t1]=tot;
}
void Dij(int st,int p){
priority_queue<Node>q;
for(int i=1;i<=n;i++)d[p][i]=inf,flag[i]=0;
d[p][st]=0;q.push((Node){st,0});
while(!q.empty()){
Node t=q.top();q.pop();
if(flag[t.x])continue;
flag[t.x]=1;
for(int i=head[t.x];i;i=e[i].nex){
if(!flag[e[i].v]&&d[p][e[i].v]>d[p][t.x]+e[i].w){
d[p][e[i].v]=d[p][t.x]+e[i].w;
q.push((Node){e[i].v,d[p][e[i].v]});
}
}
}
}
void add(int t1,int t2){
e2[++tot2].v=t2;e2[tot2].nex=HEAD[t1];HEAD[t1]=tot2;
}
void Dp(int St,int p){
queue<int>q;
q.push(St);f[p][St]=1;
for(int i=1;i<=n;i++)fl[p][i][i]=1,flag[i]=0;
while(!q.empty()){
int t=q.front();q.pop();flag[t]=1;sz+=p;
for(int i=head[t];i;i=e[i].nex){
if(flag[e[i].v])continue;
f[p][e[i].v]+=f[p][t];
fl[p][e[i].v]|=fl[p][t];
if(!(--in[p][e[i].v]))q.push(e[i].v);
}
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&S,&T);
for(int i=1,t1,t2,t3;i<=m;i++){
scanf("%d%d%d",&t1,&t2,&t3);
lj(t1,t2,t3);lj(t2,t1,t3);
}
Dij(S,0);Dij(T,1);
for(int k=1;k<=n;k++){
for(int i=head[k];i;i=e[i].nex){
if(d[0][k]+e[i].w+d[1][e[i].v]==d[0][T]){
in[0][e[i].v]++;in[1][k]++;
add(k,e[i].v),add(e[i].v,k);
}
}
}
for(int i=1;i<=tot2;i++)e[i]=e2[i];
for(int i=1;i<=n;i++)head[i]=HEAD[i];
Dp(S,0);Dp(T,1);
for(int i=1;i<=n;i++){
a[i]=f[0][i]*f[1][i];
fl[0][i]|=fl[1][i];
w[i]=a[i];
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
if(!ls[a[i]])ls[a[i]]=++cnt;
dy[cnt]=a[i];
}
for(int i=1;i<=n;i++)fs[ls[w[i]]][i]=1;
ll sum=w[S];
for(int i=1;i<=n;i++){
ll la=sum-w[i];la=ls[la];
if(!la)continue;
now=(fs[la]&fl[0][i])^fs[la];
ans+=now.count();
}
cout<<ans/2<<endl;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构