题目大意:给出一个
n
个点
考试的时候只想到按a排序后二分b…
考虑只有一种权值的情况就是做一遍类似最小生成树的东西,按权值排序后按顺序不断加边直到1,n连通
两个权值的话考虑去掉一个,于是可以枚举a,剩下一个权值b
不过权值b是无序的。a已经不用考虑了,现在的目标是使1到n的路径上的b的最大值尽量小。可以用LCT来维护一个生成树,将边变为点。加边时若两个点不连通则连接,否则找出链上最大值,若当前边更优则断掉最大后连边。然后按当前情况更新下答案就好
#include <cstdio>
#include <algorithm>
#define N 50005
#define INF 1000000000
using namespace std;
struct Edge {
int u,v,a,b;
void scan() { scanf("%d%d%d%d",&u,&v,&a,&b); }
bool operator < (const Edge& rhs) const {
return a<rhs.a;
}
}edges[N*2];
struct Node {
Node *pa,*ch[2];
int val,maxx;
bool rev_mark;
Node();
int dir();
void rev();
void pushdown();
void maintain();
}*null=new Node(),p[N],e[N*2];
Node::Node() {
val=maxx=0;
pa=ch[0]=ch[1]=null;
rev_mark=false;
}
int Node::dir() { return pa->ch[0]==this ? 0 : pa->ch[1]==this ? 1 : -1; }
void Node::rev() {
rev_mark=!rev_mark;
swap(ch[0],ch[1]);
return ;
}
void Node::pushdown() {
if(rev_mark) {
ch[0]->rev();
ch[1]->rev();
rev_mark=false;
}
return ;
}
void Node::maintain() {
maxx=val;
if(edges[ch[0]->maxx].b>edges[maxx].b) maxx=ch[0]->maxx;
if(edges[ch[1]->maxx].b>edges[maxx].b) maxx=ch[1]->maxx;
return ;
}
void Rotate(Node* o,int d) {
Node* k=o->ch[d^1]; int d2;
o->ch[d^1]=k->ch[d]; k->ch[d]->pa=o;
k->ch[d]=o;
o->maintain(), k->maintain();
if(~(d2=o->dir())) o->pa->ch[d2]=k;
k->pa=o->pa; o->pa=k;
return ;
}
void To_pushdown(Node* o) {
static Node* tmp[N];
int top=0;
while(o!=null) tmp[++top]=o, o=o->pa;
while(top) tmp[top--]->pushdown();
return ;
}
void Splay(Node* o) {
int d;
To_pushdown(o);
while(~(d=o->dir())) {
if(o->pa->dir()==d) Rotate(o->pa->pa,d^1);
Rotate(o->pa,d^1);
}
return ;
}
void Access(Node* o) {
Node* p=null;
while(o!=null) {
Splay(o);
o->ch[1]=p, o->maintain();
p=o;
o=o->pa;
}
return ;
}
void Move_to_root(Node* o) {
Access(o), Splay(o);
o->rev();
return ;
}
void Link(Node* x,Node* y) {
Move_to_root(x);
x->pa=y;
return ;
}
void Cut(Node* x,Node* y) {
Move_to_root(x);
Access(y), Splay(y);
y->ch[0]=null, y->maintain();
x->pa=null;
return ;
}
int Query_max(Node* x,Node* y) {
Move_to_root(x);
Access(y), Splay(y);
return y->maxx;
}
int n,m,ans=INF,pa[N],siz[N];
int root(int x) { return pa[x]==x ? x : pa[x]=root(pa[x]); }
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=m;++i) edges[i].scan();
sort(edges+1,edges+m+1);
for(int i=1;i<=m;++i) e[i].val=e[i].maxx=i;
for(int i=1;i<=n;++i) pa[i]=i, siz[i]=1;
for(int i=1;i<=m;++i) {
int pa_u=root(edges[i].u),pa_v=root(edges[i].v);
if(pa_u!=pa_v) {
Link(p+edges[i].u,e+i);
Link(p+edges[i].v,e+i);
if(siz[pa_u]>siz[pa_v]) swap(pa_u,pa_v);
pa[pa_u]=pa_v;
siz[pa_v]+=siz[pa_u];
}
else {
int tmp=Query_max(p+edges[i].u,p+edges[i].v);
if(edges[tmp].b>edges[i].b) {
Cut(p+edges[tmp].u,e+tmp);
Cut(p+edges[tmp].v,e+tmp);
Link(p+edges[i].u,e+i);
Link(p+edges[i].v,e+i);
}
}
int pa_st=root(1),pa_ed=root(n);
if(pa_st==pa_ed) {
int tmp=Query_max(p+1,p+n);
ans=min(ans,edges[i].a+edges[tmp].b);
}
}
if(ans==INF) ans=-1;
printf("%d\n",ans);
return 0;
}