题目大意
给定一个
n
个点
你需要找到一条从
1
到
2≤n≤5×104,0≤m≤105,1≤ai,bi≤5×104
题目分析
这题看上去就很mst套路,实际上也是mst套路。
考虑从小到大枚举路径上
ai
的最大值,然后加入满足条件的边。
如果形成了环就删掉环上
bi
最大的边。如果
1
和
使用LCT维护森林,使用并查集维护连通性。
时间复杂度
O(nlogn+nα(n))
。
代码实现
人生第一发lct居然很快就调过了,exciting!
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
#include <stack>
using namespace std;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int INF=1000000000;
const int N=50005;
const int M=100005;
const int V=N+M;
struct edge
{
int x,y,a,b;
bool operator<(edge const ed)const{return a<ed.a;}
void load(){x=read(),y=read(),a=read(),b=read();}
}edg[M];
int fa[N],rank[N];
int n,m,ans;
struct link_cut_tree
{
int par[V],fa[V],size[V],id[V],mx[V];
int son[V][2];
stack<int> st;
bool mark[V];
bool side(int x){return son[fa[x]][1]==x;}
void R(int x){swap(son[x][0],son[x][1]),mark[x]^=1;}
void clear(int x)
{
if (mark[x])
{
if (son[x][0]) R(son[x][0]);
if (son[x][1]) R(son[x][1]);
mark[x]=0;
}
}
void update(int x)
{
size[x]=size[son[x][0]]+size[son[x][1]]+1;
mx[x]=edg[mx[son[x][0]]].b>edg[mx[son[x][1]]].b?mx[son[x][0]]:mx[son[x][1]];
mx[x]=edg[id[x]].b>edg[mx[x]].b?id[x]:mx[x];
}
void pushdown(int x,int y)
{
for (;x!=y;st.push(x),x=fa[x]);
for (;!st.empty();clear(st.top()),st.pop());
}
void rotate(int x)
{
int y=fa[x];bool s=side(x);
if (fa[y]) son[fa[y]][side(y)]=x;
if (son[x][s^1]) fa[son[x][s^1]]=y;
son[y][s]=son[x][s^1],son[x][s^1]=y;
fa[x]=fa[y],fa[y]=x;
if (par[y]) par[x]=par[y],par[y]=0;
update(y),update(x);
}
void splay(int x,int y)
{
for (pushdown(x,y);fa[x]!=y;rotate(x))
if (fa[fa[x]]!=y)
if (side(x)==side(fa[x])) rotate(fa[x]);
else rotate(x);
}
int access(int x)
{
int nxt=0;
for (;x;update(nxt=x),x=par[x])
{
splay(x,0);
if (son[x][1]) fa[son[x][1]]=0,par[son[x][1]]=x;
son[x][1]=nxt;
if (nxt) fa[nxt]=x,par[nxt]=0;
}
return nxt;
}
void makeroot(int x){R(access(x));}
void link(int x,int y)
{
makeroot(x),access(x),splay(x,0);
par[x]=y,access(x);
}
void cut(int x,int y)
{
makeroot(x),access(y),splay(y,0);
fa[x]=son[y][0]=0,par[y]=0,update(y);
}
int query(int x,int y)
{
makeroot(x),access(y),splay(y,0);
return mx[y];
}
}lct;
int getfather(int son){return fa[son]==son?son:fa[son]=getfather(fa[son]);}
void merge(int x,int y)
{
if (rank[x]>rank[y]) swap(x,y);
fa[y]=x,rank[y]+=rank[x]==rank[y];
}
void calc()
{
for (int i=1;i<=n;++i) fa[i]=i;
sort(edg+1,edg+1+m),ans=INF;
for (int i=1;i<=n+m;++i) lct.size[i]=1;
for (int i=1;i<=m;++i)
{
int x=edg[i].x,y=edg[i].y,fx=getfather(x),fy=getfather(y);
if (fx!=fy) merge(fx,fy),lct.mx[i+n]=lct.id[i+n]=i,lct.link(x,i+n),lct.link(i+n,y);
else
{
int id=lct.query(x,y);
if (edg[id].b>edg[i].b)
{
int u=edg[id].x,v=edg[id].y;
lct.cut(u,id+n),lct.cut(id+n,v);
lct.mx[i+n]=lct.id[i+n]=i,lct.link(x,i+n),lct.link(i+n,y);
}
}
if (getfather(1)==getfather(n)) ans=min(ans,edg[i].a+edg[lct.query(1,n)].b);
}
}
int main()
{
freopen("forest.in","r",stdin),freopen("forest.out","w",stdout);
n=read(),m=read();
for (int i=1;i<=m;++i) edg[i].load();
calc();
if (ans==INF) printf("-1\n");
else printf("%d\n",ans);
fclose(stdin),fclose(stdout);
return 0;
}