BZOJ3669: [Noi2014]魔法森林【并查集+LCT】
3669: [Noi2014]魔法森林
【题目描述】
【题解】
我们发现只要记录这条路径上的最大值就可以了,那么我们可以强制其中一个为最大值,然后判断是否联通,更新答案(也就是将a排序,然后维护1到n中b的最大值就可以了)
可以用LCT解决,考虑这个两个节点全部被加入,那么我们用这个b替换掉这条路径上最大的b,就可以了。
【代码如下】
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=200005;
int n,m,Ans,fa[MAXN];
int get(int x){return fa[x]==x?x:fa[x]=get(fa[x]);}
struct xcw{
int x,y,a,b;
bool operator <(const xcw b)const{return a<b.a;}
}a[MAXN];
struct LCT{
int Son[MAXN][2],Fa[MAXN],Val[MAXN],ID[MAXN];bool rev[MAXN];
bool IsRoot(int rt){return Son[Fa[rt]][0]!=rt&&Son[Fa[rt]][1]!=rt;}
bool GetSon(int rt){return Son[Fa[rt]][1]==rt;}
void Clear(){for(int i=0;i<=n+m;i++){Val[i]=-(1<<30);if(i>n) Val[i]=a[i-n].b;ID[i]=i,Son[i][0]=Son[i][1]=Fa[i]=rev[i]=0;}}
void PushUp(int rt){
ID[rt]=rt;
for(int j=0;j<2;j++)
if(Val[ID[rt]]<Val[ID[Son[rt][j]]]) ID[rt]=ID[Son[rt][j]];
}
void Rotate(int rt){
int fa=Fa[rt],x=GetSon(rt);
if(!IsRoot(fa)) Son[Fa[fa]][GetSon(fa)]=rt;
Son[fa][x]=Son[rt][x^1],Fa[Son[rt][x^1]]=fa;Fa[rt]=Fa[fa];Fa[fa]=rt;Son[rt][x^1]=fa;
PushUp(fa);PushUp(rt);
}
void Flip(int rt){rev[rt]^=1;swap(Son[rt][0],Son[rt][1]);}
void PushDown(int rt){if(!rev[rt]) return;rev[rt]^=1,Flip(Son[rt][0]),Flip(Son[rt][1]);}
void DFS(int rt){if(!IsRoot(rt)) DFS(Fa[rt]);PushDown(rt);}
void Splay(int rt){for(DFS(rt);!IsRoot(rt);Rotate(rt)) if(!IsRoot(Fa[rt])) (GetSon(Fa[rt])==GetSon(rt))?Rotate(Fa[rt]):Rotate(rt);}
void Access(int rt){for(int lst=0;rt;lst=rt,rt=Fa[rt])Splay(rt),Son[rt][1]=lst,PushUp(rt);}
void Make_Root(int rt){Access(rt);Splay(rt);Flip(rt);}
void Link(int x,int y){Make_Root(x),Fa[x]=y;}
void GetPath(int x,int y){Make_Root(x),Access(y),Splay(y);}
void Cut(int x,int y){Make_Root(x),Access(y),Splay(y);Fa[x]=Son[y][0]=0;PushUp(y);}
int Ask(int x,int y){GetPath(x,y);return Val[ID[y]];}
}T;
#include<cctype>
int read(){
int ret=0;char ch=getchar();bool f=1;
for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
for(; isdigit(ch);ch=getchar()) ret=ret*10+ch-48;
return f?ret:-ret;
}
void Merge(int i){
int fx=get(a[i].x),fy=get(a[i].y);
if(fx!=fy) fa[fy]=fx,T.Link(a[i].x,i+n),T.Link(i+n,a[i].y);
else if(T.Ask(a[i].x,a[i].y)>a[i].b){
int Ed=T.ID[a[i].y];
T.Cut(a[Ed-n].x,Ed),T.Cut(Ed,a[Ed-n].y);
T.Link(a[i].x,i+n),T.Link(i+n,a[i].y);
}
}
int main(){
n=read(),m=read();
for(int i=1;i<=m;i++) a[i]=(xcw){read(),read(),read(),read()};
sort(a+1,a+1+m);T.Clear();
for(int i=1;i<=n;i++) fa[i]=i;Ans=1<<30;
for(int i=1;i<=m;i++){
Merge(i);if(get(1)!=get(n)) continue;
Ans=min(Ans,a[i].a+T.Ask(1,n));
}
if(Ans==1<<30) printf("-1\n");else printf("%d\n",Ans);
return 0;
}