P3008 [USACO11JAN]道路和飞机Roads and Planes
肯定是最短路
而且题目有限制,不存在负环
所以可以跑堆优化的Dijkstra
但是因为有负边权,所以跑得很慢
这时可以利用题目的条件
每个联通块内是没有负边权的
所以可以优先处理单个块之内的最短路
这样一个块一个块地处理
可以跑得很快
可以用Tarjan处理每个点所在的联通块
代码:
#include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> #include<queue> using namespace std; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e6+7; int n,r,p,sta; int fir[25007],from[N],to[N],val[N],cnt;//存边 inline void add(int &a,int &b,int &c) { from[++cnt]=fir[a]; fir[a]=cnt; to[cnt]=b; val[cnt]=c; } //int fa[25007]; //inline int find(int &x){ return x==fa[x] ? x : fa[x]=find(fa[x]); } //Tarjan模板 int dfs_clock,cnt2,_top,low[25002],dfn[25002],be[25002],st[25002]; inline void Tarjan(int x) { dfn[x]=low[x]=++dfs_clock; st[++_top]=x; for(int i=fir[x];i;i=from[i]) { int v=to[i]; if(!dfn[v]) Tarjan(v),low[x]=min(low[x],low[v]); else if(!be[v]) low[x]=min(low[x],dfn[v]); } if(low[x]==dfn[x]) { be[x]=++cnt2; while(st[_top]!=x) be[st[_top--]]=cnt2; --_top; } } int dis[25007]; struct node { int pos,v; bool operator < (const node &b) const{ return fa[pos]!=fa[b.pos] ? fa[pos]<fa[b.pos] : v>b.v ;//优先处理同一个块内的点 } }; priority_queue <node> q; void Dijk() { int pos,v; memset(dis,0x7f,sizeof(dis)); q.push((node){sta,0}); dis[sta]=0; while(!q.empty()) { node u=q.top(); q.pop(); if(u.v!=dis[u.pos]) continue; for(int i=fir[u.pos];i;i=from[i]) { pos=to[i],v=u.v+val[i]; if(dis[pos]>v) { dis[pos]=v; q.push((node){pos,v}); } } } } int main() { int a,b,c,xa,xb; cin>>n>>r>>p>>sta; //for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=r;i++) { a=read(); b=read(); c=read(); add(a,b,c); add(b,a,c); //xa=find(a); xb=find(b); //if(xa!=xb) fa[xa]=xb; } //for(int i=1;i<=n;i++) find(i); for(int i=1;i<=p;i++) { a=read(); b=read(); c=read(); add(a,b,c); } for(int i=1;i<=n;i++) if(!dfn[i]) Tarjan(i); Dijk(); for(int i=1;i<=n;i++) { if(dis[i]==dis[0]) printf("NO PATH\n"); else printf("%d\n",dis[i]); } return 0; }
后话:
这题一开始我处理同一块用的是并查集
但是不知道为什么就是没用,根本不能加速
总是T两个点
然后心态爆炸
直接把CRK大佬的Tarjan模板复制过来了
然后把处理联通块的步骤放到读入飞机航线之前(感觉没毛病吧,反正航线又不会形成强联通分量)
速度跟并查集一样...
把Tarjan放到读入航线后就过了....
总觉得数据有毒....