lct维护动态加点MST点这里
题目大意:
给定一个图,每条边有两个权值,ai和bi,求一条路径使得这条路径上的边的 amax+bmax a m a x + b m a x 最小。
思路:
我们首先关注若只有一个权值的做法,其实就是一种最短路,用spfa解决即可,考虑到有两个权值,我们可以按照a的从小到大枚举,并且依次加边,每加一次边之后就可以跑一遍b值得spfa,若答案产生了更新,那么一定是新加的a产生了贡献,新的答案就是dis[n]+a了。
由于是不断地加边,若新加的边对答案产生影响,那么必然经过了这条边的两个端点,这里可以采用动态加点spfa,即每次新加进去一条边之后将这条边的两个端点放入队列中更新全图的答案。
又好打又快的算法!
/*==============================
* Author : Ylsoi
* Problem : [NOI2014]magic
* File : [NOI2014]magic_spfa.cpp
* Algorithm : spfa
* Time : 2018.4.9
* ============================*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
using namespace std;
void File(){
freopen("[NOI2014]magic_spfa.in","r",stdin);
freopen("[NOI2014]magic_spfa.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define ll long long
#define inf (0x3f3f3f3f)
const int maxn=5e4+10;
const int maxm=1e5+10;
int n,m,beg[maxn],cnt,cnt1;
struct edge{int to,last,a,b;}E[maxm*2];
struct ee{
int u,v,a,b;
bool operator < (const ee &tt) const {
return a<tt.a;
}
}e[maxm];
void add(int u,int v,int a,int b){
++cnt;
E[cnt].to=v;
E[cnt].last=beg[u];
beg[u]=cnt;
E[cnt].a=a;
E[cnt].b=b;
}
int Max(int _,int __){return _>__ ? _ : __;}
int Min(int _,int __){return _<__ ? _ : __;}
int dis[maxn],ans=inf;
bool vis[maxn];
queue<int>q;
void spfa(int aa){
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=0;
MREP(i,u){
int v=E[i].to;
if(Max(dis[u],E[i].b)<dis[v]){
dis[v]=Max(dis[u],E[i].b);
if(!vis[v]){
vis[v]=1;
q.push(v);
}
}
}
}
ans=Min(ans,aa+dis[n]);
}
int main(){
File();
scanf("%d%d",&n,&m);
REP(i,1,m){
int u,v,a,b;
scanf("%d%d%d%d",&u,&v,&a,&b);
++cnt1;
e[cnt1].u=u;e[cnt1].v=v;
e[cnt1].a=a;e[cnt1].b=b;
}
sort(e+1,e+cnt1+1);
REP(i,2,n)dis[i]=inf;
int p=1;
while(p<=m){
int i=p;
while(e[i].a==e[p].a){
add(e[i].u,e[i].v,e[i].a,e[i].b);
add(e[i].v,e[i].u,e[i].a,e[i].b);
q.push(e[i].u);q.push(e[i].v);
vis[e[i].u]=1;vis[e[i].v]=1;
++i;
}
spfa(e[p].a);
p=i;
}
if(ans!=inf)printf("%d\n",ans);
else printf("%d\n",-1);
return 0;
}