您的位置:首页 > 其它

NOIP模拟 做运动【并查集+最短路】

2017-10-26 18:51 337 查看

题目大意:

给定无向图G,求在经过最大边最小的情况下S到T的最短路。

2≤n≤500000,1≤m≤1000000;

解题思路:

考试时以为最大的最小就是二分套最短路,事实证明nlog2n的复杂度要跑四五秒,gg了。

结果要求的最大边就是把所有边排序后从小到大取,使S、T联通的那一条边,接着在所有长度小于等于它的子图上跑最短路就行了。这样就是nlogn的了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
using namespace std;

int getint()
{
int i=0,f=1;char c;
for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}

const int N=500005,M=2000005;
const ll INF=2e18;
struct node
{
int x,y,t,c;
friend inline bool operator < (const node &a,const node &b)
{
return a.t<b.t;
}
}bian[M];
int n,m,S,T,mx,fa
;
int tot,first
,nxt[M],to[M],t[M],c[M];
ll dis
;
priority_queue<pair<ll,int> >q;

inline void add(int x,int y,int z,int w)
{
nxt[++tot]=first[x],first[x]=tot,to[tot]=y,t[tot]=z,c[tot]=w;
}

void dijkstra()
{
for(int i=1;i<=n;i++)dis[i]=INF;
dis[S]=0;
q.push(make_pair(0,S));
while(!q.empty())
{
int u=q.top().second;
q.pop();
if(u==T)return;
for(int e=first[u];e;e=nxt[e])
{
int v=to[e];
if(dis[v]>dis[u]+1ll*t[e]*c[e])
{
dis[v]=dis[u]+1ll*t[e]*c[e];
q.push(make_pair(-dis[v],v));
}
}
}
}

int find(int x)
{
return fa[x]==x?x:fa[x]=find(fa[x]);
}

int main()
{
//freopen("lx.in","r",stdin);
//freopen("running.out","w",stdout);
n=getint(),m=getint();
for(int i=1;i<=m;i++)
{
bian[i].x=getint();
bian[i].y=getint();
bian[i].t=getint();
bian[i].c=getint();
}
S=getint(),T=getint();
for(int i=1;i<=n;i++)fa[i]=i;
sort(bian+1,bian+m+1);
for(int i=1;i<=m;i++)
{
if(find(S)==find(T)&&bian[i].t>mx)break;
mx=bian[i].t;
add(bian[i].x,bian[i].y,bian[i].t,bian[i].c);
add(bian[i].y,bian[i].x,bian[i].t,bian[i].c);
int x=find(bian[i].x),y=find(bian[i].y);
if(x!=y)fa[y]=x;
}
dijkstra();
cout<<mx<<" "<<dis[T];
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: