前言
话说LCTLCTLCT的SplaySplaySplay和平时写的SplaySplaySplay差别好大,调了我半天
正题
题目链接:[https://www.luogu.com.cn/problem/P2387
题目大意
nnn个点mmm条边有a,ba,ba,b两个值,求一条路径从1−>n1->n1−>n使得路径上最大的aaa加上最大的bbb最小。
解题思路
我们可以将边按照aaa排序,然后枚举最大的aaa值。此时我们需要维护1−>n1->n1−>n路径上最小的bbb值,要支持动态插边。
考虑使用LCTLCTLCT,对于一条(x,y,w)(x,y,w)(x,y,w)的边,我们查询目前x,yx,yx,y之间路径上的最大边,如果该值比www大,我们断开最大边,连接该边,否则不连接即可。
codecodecode
#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);
}