luogu P3008 [USACO11JAN]Roads and Planes G
题面传送门
这道题看上去是裸的最短路。
但是众所周知,\(USACO\)经常卡\(spfa\)。
所以不能用\(spfa\)
又因为堆优化\(dj\)只能跑正权边。
所以发现一下题目的特殊性质:
事实上,由于最近恐怖主义太嚣张,为了社会和谐,出台 了一些政策保证:如果有一条航线可以从 \(A_i\)到 \(B_i\)
,那么保证不可能通过一些道路和航线从 \(B_i\)到 \(A_i\)
所以题目说没有负权环。
那我们可以把所有无向边缩成一个强联通分量,然后再强连通分量内跑堆优化\(dj\),外面跑\(toposort\)来求最短路。
这里先把每个点拓扑序跑出来然后以第一关键字为拓扑序,第二关键字为权值扔进堆中就好了。
只要跑一次堆优化\(dj\),时间复杂度\(O(mlogn)\)
代码实现:
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
int n,m,k,st,d[100039],x,y,z,flag[100039],f[100039],ans[100039],un,wn,now,cur,in[100039];
struct yyy{int to,w,z;}tmps;
struct ljb{
int head,h[100039];
yyy f[200039];
inline void add(int x,int y,int z){
f[++head]=(yyy){y,z,h[x]};
h[x]=head;
}
}s,g;
struct ques{
int to,anss,z;
bool operator<(const ques &x) const {
if(anss==x.anss) return z>x.z;
return anss>x.anss;
}
}tmp;
priority_queue<ques> q;
queue<int > qs;
inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
inline void dfs(int x){
flag[x]=1;
int cur=g.h[x];
yyy tmp;
while(cur!=-1){
tmp=g.f[cur];
in[tmp.to]++;
if(!flag[tmp.to]) dfs(tmp.to);
cur=tmp.z;
}
}
int main(){
// freopen("1.in","r",stdin);
// freopen("1.out","w",stdout);
memset(s.h,-1,sizeof(s.h));
memset(g.h,-1,sizeof(g.h));
memset(d,0x3f,sizeof(d));
register int i;
scanf("%d%d%d%d",&n,&m,&k,&st);
for(i=1;i<=n;i++) f[i]=i;
for(i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
s.add(x,y,z);s.add(y,x,z);
un=find(x);wn=find(y);
if(un!=wn) f[un]=wn;
}
for(i=1;i<=k;i++){
scanf("%d%d%d",&x,&y,&z);
s.add(x,y,z);
g.add(find(x),find(y),z);
}
dfs(find(st));
qs.push(find(st));ans[find(st)]=1;
while(!qs.empty()){
now=qs.front();
qs.pop();
cur=g.h[now];
while(cur!=-1){
tmps=g.f[cur];
in[tmps.to]--;
if(!in[tmps.to])ans[tmps.to]=ans[now]+1,qs.push(tmps.to);
cur=tmps.z;
}
}
for(i=1;i<=n;i++) ans[i]=ans[find(i)]/*,printf("%d ",ans[i])*/;
d[st]=0;
q.push((ques){st,ans[st],0});
while(!q.empty()){
tmp=q.top();
q.pop();
/*if(flag[tmp.to]) continue;
flag[tmp.to]=1;*/
//printf("%d\n",tmp.anss);
cur=s.h[tmp.to];
while(cur!=-1){
tmps=s.f[cur];
if(d[tmps.to]>d[tmp.to]+tmps.w){
//if(ans[tmps.to]<ans[tmp.to]) printf("%d\n",tmp.to);
d[tmps.to]=d[tmp.to]+tmps.w,q.push((ques){tmps.to,ans[tmps.to],d[tmps.to]});
}
cur=tmps.z;
}
}
//return 0;
for(i=1;i<=n;i++){
if(d[i]>=1e9) printf("NO PATH\n");
else printf("%d\n",d[i]);
}
}