前言
话说 的 和平时写的 差别好大,调了我半天
正题
题目链接:[https://www.luogu.com.cn/problem/P2387
题目大意
个点 条边有 两个值,求一条路径从 使得路径上最大的 加上最大的 最小。
解题思路
我们可以将边按照 排序,然后枚举最大的 值。此时我们需要维护 路径上最小的 值,要支持动态插边。
考虑使用 ,对于一条 的边,我们查询目前 之间路径上的最大边,如果该值比 大,我们断开最大边,连接该边,否则不连接即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=2e5+10;
struct node{
int x,y,a,b;
}a[N];
int n,m,val[N],sum[N],from[N],fa[N],ans;
struct Line_Cut_Tree{
#define ls t[x][0]
#define rs t[x][1]
int t[N][2],fa[N];
bool r[N];
void PushR(int x)
{r[x]^=1;swap(ls,rs);}
void PushDown(int x)
{if(r[x]){r[x]=0;PushR(ls);PushR(rs);}}
bool Nroot(int x)
{return fa[x]&&(t[fa[x]][0]==x||t[fa[x]][1]==x);}
void PushUp(int x)
{
sum[x]=val[x];from[x]=x;
if(ls&&sum[ls]>sum[x])
sum[x]=sum[ls],from[x]=from[ls];
if(rs&&sum[rs]>sum[x])
sum[x]=sum[rs],from[x]=from[rs];
}
void Rotate(int x){
int y=fa[x],z=fa[y],k=(t[y][1]==x),w=t[x][!k];
if(Nroot(y)) t[z][t[z][1]==y]=x;
t[x][!k]=y;t[y][k]=w;
if(w) fa[w]=y;fa[y]=x;fa[x]=z;
PushUp(y);PushUp(x);
return;
}
void Updata(int x)
{
if(Nroot(x))Updata(fa[x]);
PushDown(x);
}
void Splay(int x){
int y=x,z=0;
Updata(x);
while(Nroot(x)){
y=fa[x];z=fa[y];
if(Nroot(y))
Rotate((t[y][0]==x)^(t[z][0]==y)?x:y);
Rotate(x);
}
PushUp(x);
return;
}
void Access(int x)
{
for(int y=0;x;x=fa[y=x])
Splay(x),rs=y,PushUp(x);
return;
}
void MakeRoot(int x)
{Access(x);Splay(x);PushR(x);return;}
int Split(int x,int y)
{MakeRoot(x);Access(y);Splay(y);return from[y];}
void Link(int x,int y)
{MakeRoot(x);fa[x]=y;Access(x);return;}
void Cut(int x,int y)
{MakeRoot(y);Access(x);Splay(x);fa[ls]=0;ls=0;PushUp(x);return;}
#undef ls
#undef rs
}LCT;
int Find(int x)
{return fa[x]==x?x:(fa[x]=Find(fa[x]));}
bool cMp(node x,node y)
{return x.a<y.a;}
int main()
{
scanf("%d%d",&n,&m);
ans=2147483647;
for(int i=1;i<=n;i++)
fa[i]=i;
for(int i=1;i<=m;i++)
scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].a,&a[i].b);
sort(a+1,a+1+m,cMp);
for(int i=1;i<=m;i++)
val[i+n]=sum[i+n]=a[i].b,from[i+n]=i+n;
for(int i=1;i<=m;i++){
int Fa=Find(a[i].x),Fb=Find(a[i].y);
bool line=1;
if(Fa==Fb){
int p=LCT.Split(a[i].x,a[i].y);
if(sum[p]>a[i].b)
LCT.Cut(a[p-n].x,p),LCT.Cut(a[p-n].y,p);
else line=0;
}
else fa[Fa]=Fb;
if(line) LCT.Link(a[i].x,i+n),LCT.Link(a[i].y,i+n);
if(Find(1)==Find(n))
ans=min(ans,a[i].a+sum[LCT.Split(1,n)]);
}
if(ans==2147483647) printf("-1");
else printf("%d",ans);
}