传送门
题意
给一个无向图,每个边上有边权ai,bi,求一条路径,使得max(ai)+max(bi)最小。
题解
将a值排序后LCT暴力加边维护关于b值的最小生成树。
注意有一点是LCT不能维护边上的权值,只能维护点上的权值,所以要将每条连边上加一个点,Splay顺便维护最大值即可。
#include
using namespace std;
const int Maxn=5e4+50,Maxm=1e5+50;
const int INF=0x3f3f3f3f;
inline int read()
{
char ch=getchar();int i=0,f=1;
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch)){i=(i<<1)+(i<<3)+ch-'0';ch=getchar();}
return i*f;
}
struct edge
{
int x,y,a,b;
friend inline bool operator <(const edge &a,const edge &b)
{
return a.astruct node
{
node *lc,*rc,*fa;
node():lc(NULL),rc(NULL),fa(NULL){}
int val,id,tag,maxx,id2;
}Pool[Maxn+Maxm],*pool=Pool,*tr[Maxn+Maxm];
int n,m,fa[Maxn],ans=INF;
inline int getf(int x)
{
if(fa[x]==x)return x;
return fa[x]=getf(fa[x]);
}
inline void update(node *x)
{
if(x->val>=(x->lc?x->lc->maxx:0))
{
if(x->val>=(x->rc?x->rc->maxx:0))x->id2=x->id,x->maxx=x->val;
else x->id2=x->rc->id2,x->maxx=x->rc->maxx;
}
else if(x->val>=(x->rc?x->rc->maxx:0))
{
x->id2=x->lc->id2,x->maxx=x->lc->maxx;
}
else
{
if((x->rc?x->rc->maxx:0)>=(x->lc?x->lc->maxx:0))x->id2=x->rc->id2,x->maxx=x->rc->maxx;
else x->id2=x->lc->id2,x->maxx=x->lc->maxx;
}
}
inline bool isroot(node *x)
{
return (!x->fa)||(x->fa->lc!=x&&x->fa->rc!=x);
}
inline bool which(node *x)
{
return x->fa->lc!=x;
}
inline void pushdown(node *x)
{
if(x->tag)
{
swap(x->lc,x->rc);
if(x->lc)x->lc->tag^=1;
if(x->rc)x->rc->tag^=1;
x->tag^=1;
}
}
inline void rotate(node *x)
{
node *y=x->fa,*z=y->fa;
if(!isroot(y))((z->lc==y)?(z->lc):(z->rc))=x;
x->fa=z,y->fa=x;
if(y->lc==x)
{
node *b=x->rc;
x->rc=y;
y->lc=b;
if(b)b->fa=y;
}
if(y->rc==x)
{
node *b=x->lc;
x->lc=y;
y->rc=b;
if(b)b->fa=y;
}
update(y);update(x);
}
inline void splay(node *x)
{
static node* que[Maxn+Maxm];
static int tail;
que[tail=1]=x;
for(node *y=x;!isroot(y);y=y->fa)que[++tail]=y->fa;
for(int i=tail;i>=1;i--)pushdown(que[i]);
while(!isroot(x))
{
node *y=x->fa;
if(!isroot(y))
(which(x)^which(y))?(rotate(x)):(rotate(y));
rotate(x);
}
}
inline void access(node *x)
{
for(node *y=NULL;x;y=x,x=x->fa)splay(x),x->rc=y,update(x);
}
inline void makeroot(node *x)
{
access(x);splay(x);x->tag^=1;
}
inline void cut(node *x,node *y)
{
makeroot(x);access(y);splay(y);
y->lc->fa=NULL;y->lc=NULL;update(y);
}
inline void link(node *x,node *y)
{
makeroot(x);x->fa=y;
}
inline int select(node *x,node *y)
{
makeroot(x);access(y);splay(y);
return y->id2;
}
int main()
{
n=read(),m=read();
for(int i=1;i<=n;i++)tr[i]=++pool,fa[i]=i,tr[i]->id=tr[i]->id2=i;
for(int i=1;i<=m;i++)e[i].x=read(),e[i].y=read(),e[i].a=read(),e[i].b=read();
sort(e+1,e+m+1);
for(int i=1;i<=m;i++)tr[i+n]=++pool,tr[i+n]->val=e[i].b,tr[i+n]->id=tr[i+n]->id2=i+n,tr[i+n]->maxx=e[i].b;
for(int i=1;i<=m;i++)
{
int x=e[i].x,y=e[i].y,a=e[i].a,b=e[i].b;
if(x==y)continue;
if(getf(x)!=getf(y)){fa[fa[x]]=fa[y],link(tr[x],tr[i+n]);link(tr[i+n],tr[y]);}
else
{
int id=select(tr[x],tr[y]);
if(e[id-n].b>e[i].b)
{
cut(tr[x],tr[id]);cut(tr[y],tr[id]);
link(tr[x],tr[i+n]);link(tr[i+n],tr[y]);
}
}
if(getf(1)==getf(n))
{
int id=select(tr[1],tr[n]);
if(ans>e[i].a+e[id-n].b)ans=e[i].a+e[id-n].b;
}
}
printf("%d\n",(ans==INF)?(-1):ans);
}