将每条边用第一个gps认为的时间跑最短路,再用第二个gps认为的跑一遍,最后看每条边会报警几次,跑第三遍。
#include <iostream>
#include <queue>
#include <cstring>
#define int long long
using namespace std;
const int kMaxM=5e5+1;
const int kMaxN=1e5+1;
struct BIAN
{
int fr,to,p,q;
}b[kMaxM];
struct EDGE1
{
int to,nt,qu;
}e[4][kMaxM];
int cnt[4],hd[4][kMaxN];
int n,m;
int ans[4][kMaxN];
bool vis[kMaxN];
struct DIAN
{
int where,dis;
bool operator <(const DIAN &x)const
{
return x.dis<dis;
}
};
void Add(int num,int a,int b,int c)
{
e[num][++cnt[num]].to=b;
e[num][cnt[num]].nt=hd[num][a];
e[num][cnt[num]].qu=c;
hd[num][a]=cnt[num];
}
void Dij(int x)
{
priority_queue<DIAN>q;
memset(vis,0,sizeof(vis));
q.push((DIAN){1,0});
ans[x][1]=0;
while(!q.empty())
{
int now=q.top().where;
q.pop();
if(vis[now])continue;
vis[now]=true;
for(int i=hd[x][now];i;i=e[x][i].nt)
{
if(ans[x][e[x][i].to]>ans[x][now]+e[x][i].qu)
{
ans[x][e[x][i].to]=ans[x][now]+e[x][i].qu;
if(vis[e[x][i].to]==false)
{
q.push((DIAN){e[x][i].to,ans[x][e[x][i].to]});
}
}
}
}
}
signed main()
{
freopen("gpsduel.in","r",stdin);
freopen("gpsduel.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=n;i++)
{
ans[1][i]=1e17;
ans[2][i]=1e17;
ans[3][i]=1e17;
}
for(int i=1;i<=m;i++)
{
cin>>b[i].fr>>b[i].to>>b[i].p>>b[i].q;
Add(1,b[i].fr,b[i].to,b[i].p);//第一张图
Add(2,b[i].fr,b[i].to,b[i].q);//第二张图
}
Dij(1);
Dij(2);//跑两次最短路
int num=0;
for(int i=1;i<=m;i++)
{
num=0;
num+=(ans[1][b[i].to]!=ans[1][b[i].fr]+b[i].p)+(ans[2][b[i].to]!=ans[2][b[i].fr]+b[i].q);//计算每条边报警的次数,如果ans[1][b[i].to]!=ans[1][b[i].fr]+b[i].p,代表这条边不是最短路,那么经过这条边就会报警一次
Add(3,b[i].fr,b[i].to,num);//构第三张图
}
Dij(3);//再来一遍
cout<<ans[3][n];
return 0;
}