题意:
分析:
首先我们发现需要按 (a,b) 的大小动态加减边,直到 1 和 (n) 联通,所以上 LCT
具体做法就是,把边按 (a) 升序排好后,从小到大加边,每次新加入一条边 (u -> v) 时,分两种情况:
- 在同一个连通块内
此时删掉连通块里 b 最大的那条边,然后加入这条边
- 不在一个连通块内部
直接 (link) 就好了
然鹅,我们发现一个大问题,LCT 是用来维护点权的,而我们需要对边权进行查询,怎么办呢?很简单,就是新建一个节点表示边
对于 (u->v) 等价于 (link(i,u),link(i,v)) 把边权转化为 (i) 的点权
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define mk(x,y) make_pair(x,y)
#define fir first
#define sec second
using namespace std;
namespace zzc
{
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
const int maxn = 2e5+5;
int n,m,cnt,ans=0x3f3f3f;
pii tmp[maxn];
struct edge
{
int frm,to,va,vb;
}e[maxn];
bool cmp(edge a,edge b)
{
return a.va==b.va?a.vb<b.vb:a.va<b.va;
}
namespace lct
{
int top,q[maxn],fa[maxn],c[maxn][2],rev[maxn];
pii val[maxn];
void pushup(int x){val[x]=max(tmp[x],max(val[c[x][0]],val[c[x][1]]));}
void pushdown(int x)
{
int l=c[x][0],r=c[x][1];
if(rev[x])
{
rev[l]^=1;rev[r]^=1;rev[x]^=1;
swap(c[x][0],c[x][1]);
}
}
bool isroot(int x){return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;}
void rotate(int x)
{
int y=fa[x],z=fa[y],l,r;
if(c[y][0]==x)l=0;else l=1;r=l^1;
if(!isroot(y)){if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;}
fa[y]=x;fa[x]=z;fa[c[x][r]]=y;
c[y][l]=c[x][r];c[x][r]=y;
pushup(y);pushup(x);
}
void splay(int x)
{
top=1;q[top]=x;
for(int i=x;!isroot(i);i=fa[i]) q[++top]=fa[i];
for(int i=top;i;i--) pushdown(q[i]);
while(!isroot(x))
{
int y=fa[x],z=fa[y];
if(!isroot(y))
{
if((c[z][0]==y)^(c[y][0]==x)) rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x){for(int t=0;x;t=x,x=fa[x])splay(x),c[x][1]=t,pushup(x);}
void makeroot(int x){access(x);splay(x);rev[x]^=1;}
int find(int x){access(x);splay(x);while(c[x][0])x=c[x][0];splay(x);return x;}
void split(int x,int y){makeroot(x);access(y);splay(y);}
void cut(int x,int y){split(x,y);if(c[y][0]==x&&c[x][1]==0)c[y][0]=0,fa[x]=0,pushup(y);}
void link(int x,int y){makeroot(x);fa[x]=y;}
}
using namespace lct;
void work()
{
n=read();m=read();
for(int i=1;i<=m;i++)e[i].frm=read(),e[i].to=read(),e[i].va=read(),e[i].vb=read();
sort(e+1,e+m+1,cmp);
for(int i=1;i<=m;i++)
{
tmp[i+n].fir=e[i].vb;tmp[i+n].sec=i+n;
int u=e[i].frm,v=e[i].to;
bool flag=true;
makeroot(u);
if(find(u)==find(v))
{
split(u,v);
int id=val[v].sec;
if(tmp[id].fir>e[i].vb)
{
cut(id,e[id-n].frm);
cut(id,e[id-n].to);
}
else flag=false;
}
if(flag) link(i+n,u),link(i+n,v);
makeroot(1);
if(find(n)==1)
{
split(1,n),ans=min(ans,e[i].va+val[n].fir);
}
}
if(ans==0x3f3f3f) printf("-1
");
else printf("%d
",ans);
}
}
int main()
{
zzc::work();
return 0;
}