定义
lct就是使用很多棵splay来维护树形结构及其链上信息的数据结构。
操作
access
就是将一个点和根节点的路径用一棵splay联系在一起,没有其他多余的节点。我们的每一棵splay都是维护一条往上的树链,其中深度较小的在splay的左边。每一个splay最左端点都维护一个指针,指向原树中的父亲,这样access就是一些splay的合并。
makeroot
就是将一个点x变成树的根节点,先access一下,发现和splay相连的树边和splay的形态没有关系,改变根节点只需要splay全树翻转即可。
link
将两个点都makeroot,用指针连一下即可,权值在边上的时候新建一个点存放权值即可。
cut
对一个点access一下,目标边变成虚边之后直接删掉即可。
code
在此以【NOI2014】【魔法森林】为例。
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LF double
#define LL long long
#define ULL unsigned long long
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define fr(i,j,k) for(int i=begin[j][k];i;i=next[j][i])
using namespace std;
int const mn=5*1e4+9,mm=1e5,mp=1.5*1e5,inf=1e9+7;
int n,m,setfa[mn],val[mp],mx[mp],over[mp],fa[mp],par[mp],son[mp][2];
struct rec{
int x,y,a,b;
};
rec a[mm];
bool cmp(rec x,rec y){
return x.a<y.a;
}
void retag(int now){
if(over[now]){
over[now]=0;
swap(son[now][0],son[now][1]);
over[son[now][0]]^=1;
over[son[now][1]]^=1;
}
}
void update(int now){
if(now){
int tmp=mx[son[now][0]],tm2=mx[son[now][1]];
mx[now]=(val[tmp]>val[tm2])?tmp:tm2;
mx[now]=(val[now]>val[mx[now]])?now:mx[now];
}
}
int side(int now){
int tmp=fa[now];
return son[tmp][1]==now;
}
void rotate(int now){
int tmp=fa[now],si=side(now);
son[fa[tmp]][side(tmp)]=now;
fa[now]=fa[tmp];
son[tmp][si]=son[now][!si];
fa[son[now][!si]]=tmp;
son[now][!si]=tmp;
fa[tmp]=now;
update(tmp);
update(now);
}
void splay(int now,int root){
while(fa[now]!=root){
int tmp=fa[now];
if(fa[tmp]!=root){
retag(fa[tmp]);retag(tmp);retag(now);
if(side(now)==side(tmp))rotate(tmp);
else rotate(now);
}
retag(tmp);retag(now);
rotate(now);
}
}
int first(int now){
retag(now);
while(son[now][0]){
now=son[now][0];
retag(now);
}
return now;
}
void indep(int now){
splay(now,0);
if(!son[now][1])return;
int tmp=first(son[now][1]);
splay(tmp,now);
son[now][1]=fa[tmp]=0;
par[tmp]=now;
update(now);
}
void access(int now){
indep(now);
while(par[now=first(now)]){
splay(now,0);
int tmp=par[now];
indep(tmp);
son[tmp][1]=now;
fa[now]=tmp;
par[now]=0;
update(tmp);
now=tmp;
}
}
void makeroot(int now){
access(now);
splay(now,0);
over[now]^=1;
retag(now);
}
int get(int now){
if(!setfa[now])return now;
return setfa[now]=get(setfa[now]);
}
int main(){
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,m)scanf("%d%d%d%d",&a[i].x,&a[i].y,&a[i].a,&a[i].b);
sort(a+1,a+m+1,cmp);
int ans=inf;
fo(i,1,m){
int fx=get(a[i].x),fy=get(a[i].y),tag=0;
if(fx==fy){
makeroot(a[i].x);
access(a[i].y);
splay(a[i].y,0);
int tmp=mx[a[i].y];
if(val[tmp]>a[i].b){
splay(tmp,0);tag=1;
fa[son[tmp][0]]=fa[son[tmp][1]]=0;
}
}else setfa[fx]=fy;
if((fx!=fy)||tag){
makeroot(a[i].x);
makeroot(a[i].y);
val[n+i]=a[i].b;
par[a[i].x]=n+i;
par[n+i]=a[i].y;
}
if(get(1)==get(n)){
makeroot(1);
access(n);
splay(n,0);
ans=min(ans,a[i].a+val[mx[n]]);
}
}
if(ans==inf)printf("-1");
else printf("%d",ans);
return 0;
}