BZOJ3669 题面
从更简单的情况入手,如果边权只有 a 没有 b 应该怎么处理?这时候问题就是找一条从1到N的路径,使得最长的边尽量短。根据最小生成树的性质,这样的边一定在最小生成树上。
如果 a 固定,得到的解法是一样的。那么可以分别讨论每一个 a ,对于权值不大于 a 的边对 b 做一次最小生成树。暴力做会超时。考虑到随着 a 的变大,可用的边也逐渐增多,那么只要在加边的同时更新最小生成树就可以了。这个操作可以用LCT处理。
#include
#include
#define MAXN 150005
#define MAXM 200005
using namespace std;
int N,M,Ans=1e9;
struct node{int st,en,va,vb;}edge[MAXM];
bool operator<(node x,node y)
{
if(x.va==y.va)return x.vbreturn x.vaint ls[MAXN],rs[MAXN],fa[MAXN],rev[MAXN],val[MAXN];
int Max[MAXN],id[MAXN];
bool isrt(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
void Update(int p)
{
if(Max[ls[p]]>Max[rs[p]])Max[p]=Max[ls[p]],id[p]=id[ls[p]];
else Max[p]=Max[rs[p]],id[p]=id[rs[p]];
if(Max[p]void Putdown(int p)
{
if(rev[p]==0)return;
rev[ls[p]]^=1;rev[rs[p]]^=1;rev[p]=0;
swap(ls[p],rs[p]);
}
void Zig(int x)
{
int y=fa[x],z=fa[y];
if(!isrt(y))
{
if(ls[z]==y)ls[z]=x;
else rs[z]=x;
}
fa[x]=z;fa[y]=x;fa[rs[x]]=y;
ls[y]=rs[x];rs[x]=y;
Update(y);Update(x);
}
void Zag(int x)
{
int y=fa[x],z=fa[y];
if(!isrt(y))
{
if(ls[z]==y)ls[z]=x;
else rs[z]=x;
}
fa[x]=z;fa[y]=x;fa[ls[x]]=y;
rs[y]=ls[x];ls[x]=y;
Update(y);Update(x);
}
int s[MAXN],Top;
void Splay(int x)
{
int i,y,z;
s[++Top]=x;
for(i=x;!isrt(i);i=fa[i])s[++Top]=fa[i];
while(Top)Putdown(s[Top--]);
while(!isrt(x))
{
y=fa[x];z=fa[y];
if(isrt(y))
{
if(ls[y]==x)Zig(x);
else Zag(x);
}
else
{
if(ls[z]==y)
{
if(ls[y]==x)Zig(y),Zig(x);
else Zag(x),Zig(x);
}
else
{
if(rs[y]==x)Zag(y),Zag(x);
else Zig(x),Zag(x);
}
}
}
}
void Access(int x)
{
int t=0;
while(x)
{
Splay(x);
rs[x]=t;Update(x);
t=x;x=fa[x];
}
}
void SetRt(int x)
{
Access(x);Splay(x);rev[x]^=1;
}
void Link(int x,int y)
{
SetRt(x);fa[x]=y;
}
void Cut(int x,int y)
{
SetRt(x);
Access(y);Splay(y);
ls[y]=fa[x]=0;
Update(y);
}
int FindRt(int x)
{
Access(x);Splay(x);
while(ls[x])x=ls[x];
return x;
}
int tot,lk[MAXM][2];
void Add(int x,int y,int v)
{
tot++;
lk[tot][0]=x;lk[tot][1]=y;
val[tot]=v;id[tot]=tot;
Link(x,tot);Link(tot,y);
}
void Del(int x)
{
Cut(x,lk[x][0]);Cut(x,lk[x][1]);
}
int GetMax(int x,int y,int op)
{
SetRt(x);
Access(y);Splay(y);
if(op==1)return Max[y];
else return id[y];
}
int main()
{
int i,j;
scanf("%d%d",&N,&M);
for(i=1;i<=M;i++)scanf("%d%d%d%d",&edge[i].st,&edge[i].en,&edge[i].va,&edge[i].vb);
sort(edge+1,edge+M+1);
tot=N;
for(i=j=1;i<=50000;i++)
{
while(j<=M&&edge[j].va<=i)
{
int x,y;
if(edge[j].st==edge[j].en){j++;continue;}
x=FindRt(edge[j].st);
y=FindRt(edge[j].en);
if(x!=y)Add(edge[j].st,edge[j].en,edge[j].vb);
else
{
int tmp=GetMax(edge[j].st,edge[j].en,1);
if(tmp>edge[j].vb)
{
tmp=GetMax(edge[j].st,edge[j].en,2);
Del(tmp);Add(edge[j].st,edge[j].en,edge[j].vb);
}
}
j++;
}
if(FindRt(1)!=FindRt(N))continue;
Ans=min(Ans,i+GetMax(1,N,1));
}
if(Ans==1e9)puts("-1");
else printf("%d\n",Ans);
}