把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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]);
   }
}
posted @ 2020-07-08 21:58  275307894a  阅读(48)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end