首先这道题的生成树部分还是比较好想的,如果只有(a)或(b)一个限制,那么我们求一个最小生成树最小化最大边权
有两个限制的话我们先对(a)求出最小生成树,考虑把没有加入最小生成树的边加进去,显然会使得(1)到(n)之间最大的(b)变小,就把剩下的边一条一条加进去,维护出(1)到(n)之间的最大边权
(lct)维护的是点的信息,处理边权的话我们不能像树剖那样把一条边的信息存在一个儿子里,因为树的结构时刻在变化,所以我们得把每一条边当成
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 1500005
#define re register
#define inf 999999999
#define LL long long
#define max std::max
#define min std::min
#define pt putchar(1)
inline int read() {
char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int n,m,ans;
struct E{int u,v,a,b;} e[maxn];
inline int cmp(E A,E B) {return A.a<B.a;}
int ch[maxn][2],rev[maxn],fa[maxn],d[maxn],st[maxn];
inline int nroot(int x) {return ch[fa[x]][1]==x||ch[fa[x]][0]==x;}
inline void pushup(int x) {
d[x]=x;
if(e[d[x]].b<e[d[ch[x][0]]].b) d[x]=d[ch[x][0]];
if(e[d[x]].b<e[d[ch[x][1]]].b) d[x]=d[ch[x][1]];
}
inline void pushdown(int x) {
if(!rev[x]) return;
rev[x]=0,rev[ch[x][0]]^=1,rev[ch[x][1]]^=1;
if(ch[x][0]) std::swap(ch[ch[x][0]][0],ch[ch[x][0]][1]);
if(ch[x][1]) std::swap(ch[ch[x][1]][0],ch[ch[x][1]][1]);
}
inline void rotate(int x) {
int y=fa[x],z=fa[y],k=ch[y][1]==x,w=ch[x][k^1];
if(nroot(y)) ch[z][ch[z][1]==y]=x;
ch[x][k^1]=y,ch[y][k]=w;
pushup(y),pushup(x);fa[w]=y;fa[y]=x,fa[x]=z;
}
inline void splay(int x) {
int y=x,top=0;
st[++top]=x;
while(nroot(y)) st[++top]=fa[y],y=fa[y];
while(top) pushdown(st[top--]);
while(nroot(x)) {
int y=fa[x];
//printf("%d %d
",x,y);
if(nroot(y)) rotate((ch[y][1]==x)^(ch[fa[y]][1]==y)?x:y);
rotate(x);
}
//putchar(10);
}
inline void access(int x) {
for(re int y=0;x;y=x,x=fa[x])
splay(x),ch[x][1]=y,pushup(x);
}
inline void makeroot(int x) {
access(x);splay(x);rev[x]^=1;std::swap(ch[x][0],ch[x][1]);
}
inline int findroot(int x) {
access(x);splay(x);
while(ch[x][0]) pushdown(x),x=ch[x][0];
return x;
}
inline void split(int x,int y) {
makeroot(x);access(y);splay(y);
}
inline void link(int x,int y) {
makeroot(x);fa[x]=y;
}
inline void cut(int x,int y) {
split(x,y);ch[y][0]=fa[x]=0,pushup(y);
}
int main()
{
n=read(),m=read();ans=inf;
for(re int i=1;i<=m;i++)
e[i].u=read()+m,e[i].v=read()+m,e[i].a=read(),e[i].b=read();
std::sort(e+1,e+m+1,cmp);
for(re int i=1;i<=m;i++) {
int x=e[i].u,y=e[i].v;
if(findroot(x)!=findroot(y)) link(x,i),link(y,i);
else {
split(x,y);int t=d[y];
if(e[i].b<e[d[y]].b) cut(e[t].u,t),cut(e[t].v,t),link(x,i),link(y,i);
}
if(findroot(m+1)==findroot(n+m))
split(m+1,n+m),ans=min(ans,e[i].a+e[d[n+m]].b);
}
if(ans!=inf) printf("%d
",ans);else puts("-1");
return 0;
}