题目大意
给定N个点M条边的无向图,每条边有两个权值a与b。求一条1到n的路径使得路径经过边的最大a与最大b的和最小。无法到达输出-1。
n<=50000,m<=100000。ai,bi<=50000
分析
看到ai这么小,我们考虑枚举ai然后算最小b。
那么从小到大枚举ai,不断加入边,边权为bi。
用LCT维护最小生成树即可。具体的,新加入一条边(x,y),若不在同一联通块就link,在同一联通块看看路径上是否有权值比bi大的,找到最大的,cut,再link(x,y)
若1和n在同一联通块,就算1到n简单路径的大权值,加上ai更新答案。
实现技巧:边权不好维护,我们把边拆成一个点两条边,点权为边权,两条边连向原来两点。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
const int N=200005;
struct rec
{
int x,y,a,b;
}b[N];
int tr[N][2],tag[N],tmax[N],tval[N],tsiz[N],up[N],tup[N],sta[N],st;
int dad[N],rx,ry;
int xx,yy,ans,pp,x,y,z,i,j,n,m,pos;
bool cmp(rec a,rec b)
{
return a.a<b.a;
}
int get(int x)
{
if (dad[x]==x) return x;
return dad[x]=get(dad[x]);
}
int pd(int x)
{
return tr[up[x]][1]==x;
}
void down(int x)
{
if (!tag[x]) return;
swap(tr[x][0],tr[x][1]);
tag[tr[x][0]]^=1;
tag[tr[x][1]]^=1;
tag[0]=tag[x]=0;
}
void update(int x)
{
int ls=tr[x][0],rs=tr[x][1];
tsiz[x]=tsiz[ls]+tsiz[rs]+1;
if (tval[tmax[ls]]>tval[tmax[rs]]) tmax[x]=tmax[ls];else tmax[x]=tmax[rs];
if (tval[x]>tval[tmax[x]]) tmax[x]=x;
}
void rotate(int x)
{
int y=up[x],z;
z=pd(x);
up[x]=up[y];
if (up[x]) tr[up[x]][pd(y)]=x;
tr[y][z]=tr[x][1-z];
if (tr[y][z]) up[tr[y][z]]=y;
tr[x][1-z]=y;
up[y]=x;
update(y);
update(x);
if (tup[y]) tup[x]=tup[y];
tup[y]=0;
}
void remove(int x,int y)
{
st=1;
sta[1]=x;
while (x!=y)
sta[++st]=(x=up[x]);
while (st)
down(sta[st--]);
}
void splay(int x,int y)
{
remove(x,y);
while (up[x]!=y)
{
if (up[up[x]]!=y)
{
if (pd(x)==pd(up[x]))
rotate(up[x]);
else rotate(x);
}
rotate(x);
}
}
void access(int x)
{
int last=0,z=x;
while (x)
{
splay(x,0);
up[tr[x][1]]=0;
if (tr[x][1]) tup[tr[x][1]]=x;
tr[x][1]=last;
tup[last]=0;
if (last)
up[last]=x;
update(x);
last=x;
x=tup[x];
}
splay(z,0);
}
void makeroot(int x)
{
access(x);
tag[x]^=1;
}
void cut(int x,int y)
{
makeroot(x);
access(y);
if (tr[y][0]) up[tr[y][0]]=0;
tr[y][0]=0;
}
void link(int x,int y)
{
makeroot(x);
//access(y);
splay(x,0);
tup[x]=y;
}
int main()
{
freopen("3754.in","r",stdin);
scanf("%d %d",&n,&m);
fo(i,1,m)
scanf("%d %d %d %d",&b[i].x,&b[i].y,&b[i].a,&b[i].b);
sort(b+1,b+1+m,cmp);
ans=N;
fo(i,1,n+m) dad[i]=i;
fo(i,1,m)
{
if (b[i].x==b[i].y) continue;
x=b[i].x;
y=b[i].y;
tval[i+n]=b[i].b;
tmax[i+n]=i+n;
rx=get(x);
ry=get(y);
if (rx!=ry)
{
dad[rx]=ry;
link(i+n,x);
link(i+n,y);
}else
{
makeroot(x);
access(y);
if (tval[tmax[y]]>b[i].b)
{
z=tmax[y];
cut(z,b[z-n].x);
cut(z,b[z-n].y);
link(i+n,x);
link(i+n,y);
}
}
if (get(1)==get(n))
{
makeroot(1);
access(n);
splay(n,0);
ans=min(ans,b[i].a+tval[tmax[n]]);
}
}
if (ans==N) ans=-1;
printf("%d\n",ans);
}