把每条边的ai从小到大排序
然后不断插入每一条边,然后就是要维护是的1到n的路径中最大的bi最小
首先我们肯定是要把转化成一棵树的,对于新插入的一条边,如果两个点本来就不连通,那么就直接插入,如果联通那么插入以后就会形成一个换,我们只要再把换上的最大的边删掉,这个用动态树维护即可。
对于细节的处理,可以采用以点代边的做法,即多开m个点表示边(编号为n+1~n+m),插入一条边就是连接(u,n+i)和(n+i,v),边权就放在表示边的点上。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#define rep(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
template<typename T>inline void qr(T &x){
x=0;int f=0;char s=getchar();
while(s<'0'||'9'<s)f|=s=='-',s=getchar();
while('0'<=s&&s<='9')x=x*10+s-48,s=getchar();
x=f?-x:x;
}
const int mxn=150010;
const int inf=1e9;
struct edge{int x,y,a,b;}e[mxn];
int fa[mxn],dat[mxn],id[mxn],ch[mxn][2];bool fz[mxn];
int n,m,num,ans,w[mxn],st[mxn];
bool cmp(edge p1,edge p2){
return p1.a<p2.a;
}
#define lc ch[x][0]
#define rc ch[x][1]
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
bool nrt(int x){return ls(fa[x])==x||rs(fa[x])==x;}
void update(int x){
dat[x]=w[x],id[x]=x;
if(lc&&dat[lc]>dat[x])dat[x]=dat[lc],id[x]=id[lc];
if(rc&&dat[rc]>dat[x])dat[x]=dat[rc],id[x]=id[rc];
}
void rev(int x){
swap(lc,rc);
fz[x]^=1;
}
void pushdown(int x){
if(fz[x]){
rev(lc),rev(rc);
fz[x]=0;
}
}
void rotate(int x){
int y=fa[x],z=fa[y],k=(rs(y)==x);
if(nrt(y))ch[z][rs(z)==y]=x;fa[x]=z;
fa[ch[y][k]=ch[x][1-k]]=y;
ch[x][1-k]=y,fa[y]=x;
update(y);
}
void splay(int x){
int tp=0,now=x;st[++tp]=now;
while(nrt(now))st[++tp]=now=fa[now];
while(tp)pushdown(st[tp--]);
while(nrt(x)){
int y=fa[x],z=fa[y];
if(nrt(y))
(rs(z)==y)^(rs(y)==x)?rotate(x):rotate(y);
rotate(x);
}
update(x);
}
void access(int x){
for(int y=0;x;x=fa[y=x])
splay(x),rc=y,update(x);
}
void makeroot(int x){
access(x);
splay(x);
rev(x);
}
int findroot(int x){
access(x);
splay(x);
pushdown(x);
while(lc)pushdown(x=lc);
return x;
}
void split(int x,int y){
makeroot(x);
access(y);
splay(y);
}
void link(int x,int y){
makeroot(x);
if(findroot(y)!=x)fa[x]=y;
}
bool check(int x,int y){
makeroot(x);
return findroot(y)!=x;
}
int main(){
qr(n),qr(m),ans=inf;
rep(i,1,m)qr(e[i].x),qr(e[i].y),qr(e[i].a),qr(e[i].b);
sort(e+1,e+m+1,cmp);
rep(i,1,m){
w[i+n]=e[i].b;
if(e[i].x==e[i].y)continue;
if(check(e[i].x,e[i].y))link(e[i].x,i+n),link(i+n,e[i].y);
else{
split(e[i].x,e[i].y);
int now=id[e[i].y],mxb=dat[e[i].y];
if(mxb<=e[i].b)continue;
splay(now),fa[ls(now)]=fa[rs(now)]=0;
link(e[i].x,i+n),link(i+n,e[i].y);
}
if(!check(1,n)){
split(1,n);
ans=min(ans,dat[n]+e[i].a);
}
}
if(ans==inf)ans=-1;
printf("%d\n",ans);
return 0;
}