[学习笔记]Link-Cut Tree

我终于理解了 \(LCT\)!!!想不到小蒟蒻有一天理解了!!!

存个板子

#include <bits/stdc++.h>
using namespace std;
const int maxn=300000+10;
int n,m,a[maxn],ch[maxn][2],fa[maxn],val[maxn],sta[maxn],top;
bool rev[maxn];

inline void reverse(int x){
	swap(ch[x][0],ch[x][1]);
	rev[x]^=1;
}
inline void pushup(int x){
	val[x]=val[ch[x][0]]^val[ch[x][1]]^a[x];
}
inline void pushdown(int x){
	if(rev[x]){
		rev[x]=0;
		if(ch[x][0]) reverse(ch[x][0]);
		if(ch[x][1]) reverse(ch[x][1]);
	}
}
inline bool nrt(int x){
	return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
}
inline void rotate(int x){
	int y=fa[x],z=fa[y],k=(x==ch[y][1]),u=ch[x][k^1];
	if(nrt(y)) ch[z][ch[z][1]==y]=x;
	ch[y][k]=u;ch[x][k^1]=y;
	if(u) fa[u]=y;fa[y]=x;fa[x]=z;
	val[x]=val[y];pushup(y);
}
inline void splay(int x){
	int y,z;top=0;
	for(y=x;nrt(y);y=fa[y]) sta[top++]=y;
	pushdown(y);
	while(top) pushdown(sta[--top]);
	while(nrt(x)){
		y=fa[x],z=fa[y];
		if(nrt(y)) rotate((ch[y][1]==x)^(ch[z][1]==y)?x:y);
		rotate(x);
	}
}
inline void access(int x){
	int y=0;
	for(;x;y=x,x=fa[x])
		splay(x),ch[x][1]=y,pushup(x);
}
inline void makeroot(int x){
	access(x),splay(x),reverse(x);
}
inline int findroot(int x){
	access(x),splay(x);
	for(;ch[x][0];x=ch[x][0]) pushdown(x);
	return x;
}
inline void split(int x,int y){
	makeroot(x),access(y),splay(y);
}
inline void link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x)
		fa[x]=y,pushup(y);
}
inline void cut(int x,int y){
	makeroot(x);
	if(findroot(y)==x&&fa[x]==y&&!ch[x][1])
		fa[x]=ch[y][0]=0,pushup(y);
}
inline int read(){
	register int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return (f==1)?x:-x;
}

int main()
{
	n=read(),m=read();
	for(int i=1;i<=n;i++){
		val[i]=a[i]=read();
		fa[i]=ch[i][0]=ch[i][1]=0;
	}
	int opt,x,y;
	for(int i=1;i<=m;i++){
		opt=read(),x=read(),y=read();
		if(opt==0) split(x,y),printf("%d\n",val[y]);
		if(opt==1) link(x,y);
		if(opt==2) cut(x,y);
		if(opt==3) splay(x),a[x]=y,pushup(x);
	}
	return 0;
}

2、[COCI 2009] OTOCI / 极地旅行社

其实就是 \(pushup\) 改了一下

\(Code\ Below:\)

#include <bits/stdc++.h>
using namespace std;
const int maxn=30000+10;
int n,q,a[maxn],ch[maxn][2],fa[maxn],val[maxn],sta[maxn],top;
bool rev[maxn];

inline int read(){
	register int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return (f==1)?x:-x;
}
inline void reverse(int x){
	swap(ch[x][0],ch[x][1]);
	rev[x]^=1;
}
inline void pushup(int x){
	val[x]=val[ch[x][0]]+val[ch[x][1]]+a[x];
}
inline void pushdown(int x){
	if(rev[x]){
		rev[x]=0;
		if(ch[x][0]) reverse(ch[x][0]);
		if(ch[x][1]) reverse(ch[x][1]);
	}
}
inline bool nrt(int x){
	return ch[fa[x]][0]==x||ch[fa[x]][1]==x;
}
inline void rotate(int x){
	int y=fa[x],z=fa[y],k=(x==ch[y][1]),u=ch[x][k^1];
	if(nrt(y)) ch[z][ch[z][1]==y]=x;
	ch[y][k]=u;ch[x][k^1]=y;
	if(u) fa[u]=y;fa[y]=x;fa[x]=z;
	val[x]=val[y];pushup(y);
}
inline void splay(int x){
	int y,z;top=0;
	for(y=x;nrt(y);y=fa[y]) sta[top++]=y;
	pushdown(y);
	while(top) pushdown(sta[--top]);
	while(nrt(x)){
		y=fa[x],z=fa[y];
		if(nrt(y)) rotate((ch[y][1]==x)^(ch[z][1]==y)?x:y);
		rotate(x);
	}
}
inline void access(int x){
	int y=0;
	for(;x;y=x,x=fa[x])
		splay(x),ch[x][1]=y,pushup(x);
}
inline void makeroot(int x){
	access(x),splay(x),reverse(x);
}
inline int findroot(int x){
	access(x),splay(x);
	for(;ch[x][0];x=ch[x][0]) pushdown(x);
	return x;
}
inline void split(int x,int y){
	makeroot(x),access(y),splay(y);
}
inline int link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x){
		fa[x]=y,pushup(y);
		return 1;
	}
	return 0;
}
inline void cut(int x,int y){
	makeroot(x);
	if(findroot(y)==x&&fa[x]==y&&!ch[x][1])
		fa[x]=ch[y][0]=0,pushup(y);
}

int main()
{
	n=read();
	for(int i=1;i<=n;i++)
		val[i]=a[i]=read();
	char opt[20];int x,y;
	q=read();
	for(int i=1;i<=q;i++){
		scanf("%s",opt);
		x=read(),y=read();
		if(opt[0]=='b'){
			if(link(x,y)) printf("yes\n");
			else printf("no\n");
		}
		if(opt[0]=='p'){
			splay(x),a[x]=y,pushup(x);
		}
		if(opt[0]=='e'){
			makeroot(x);
			if(findroot(y)!=x)
				printf("impossible\n");
			else split(x,y),printf("%d\n",val[y]);
		}
	}
	return 0;
}

3、[WC2006]水管局长

删边操作不好处理,所以倒过来。

动态查询最大边权的最小值,先做一遍 \(Kruskal\),然后每次选一条最大的边权,如果当前加边的边权比最大的边权小,那么 \(Cut\) 掉原来的边然后 \(Link\) 一下现在的边。

边权不好处理,还要转化成点权,用虚点法。

\(Code\ Below:\)

#include <bits/stdc++.h>
#define pii pair<int,int>
using namespace std;
const int maxn=1000000+10;
int n,m,Q,ch[maxn][2],fa[maxn],val[maxn],Max[maxn],sta[maxn],f[maxn],ans[maxn],top;
bool rev[maxn],vis[maxn];
struct Edge{
    int x,y,w;
}e[maxn];
struct Query{
    int op,x,y,id;
}q[maxn];
map<pii,int> mp;
bool cmp(Edge a,Edge b){
    return a.w<b.w;
}
inline int read(){
    register int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return (f==1)?x:-x;
}
inline void reverse(int x){
    swap(ch[x][0],ch[x][1]);
    rev[x]^=1;
}
inline void pushup(int x){
    Max[x]=x;
    if(val[Max[ch[x][0]]]>val[Max[x]]) Max[x]=Max[ch[x][0]];
    if(val[Max[ch[x][1]]]>val[Max[x]]) Max[x]=Max[ch[x][1]];
}
inline void pushdown(int x){
    if(rev[x]){
        rev[x]=0;
        if(ch[x][0]) reverse(ch[x][0]);
        if(ch[x][1]) reverse(ch[x][1]);
    }
}
inline bool nrt(int x){
    return x==ch[fa[x]][0]||x==ch[fa[x]][1];
}
inline void rotate(int x){
    int y=fa[x],z=fa[y],k=(x==ch[y][1]),u=ch[x][k^1];
    if(nrt(y)) ch[z][ch[z][1]==y]=x;
    ch[y][k]=u;ch[x][k^1]=y;
    if(u) fa[u]=y;fa[y]=x;fa[x]=z;
    pushup(y);pushup(x);
}
inline void splay(int x){
    int y,z;top=0;
    for(y=x;nrt(y);y=fa[y]) sta[++top]=y;
    pushdown(y);
    while(top) pushdown(sta[top--]);
    while(nrt(x)){
        y=fa[x],z=fa[y];
        if(nrt(y)) rotate((x==ch[y][1])^(y==ch[z][1])?x:y);
        rotate(x);
    }
}
inline void access(int x){
    int y=0;
    for(;x;y=x,x=fa[x])
        splay(x),ch[x][1]=y,pushup(x);
}
inline void makeroot(int x){
    access(x),splay(x),reverse(x);
}
inline int findroot(int x){
    access(x),splay(x);
    for(;ch[x][0];x=ch[x][0]) pushdown(x);
    return x;
}
inline void split(int x,int y){
    makeroot(x),access(y),splay(y);
}
inline void link(int x,int y){
    makeroot(x);
    if(findroot(y)!=x)
        fa[x]=y,pushup(y);
}
inline void cut(int x,int y){
    makeroot(x);
    if(findroot(y)==x&&fa[x]==y&&!ch[y][1])
        fa[x]=ch[y][0]=0,pushup(y);
}
int find(int x){
    return (x==f[x])?x:f[x]=find(f[x]);
}

int main()
{
    n=read(),m=read(),Q=read();
    for(int i=1;i<=m;i++){
        e[i].x=read(),e[i].y=read(),e[i].w=read();
        if(e[i].x>e[i].y) swap(e[i].x,e[i].y);
    }
    sort(e+1,e+m+1,cmp);
    for(int i=1;i<=m;i++){
        mp[make_pair(e[i].x,e[i].y)]=i;
        val[i+n]=e[i].w;Max[i+n]=i+n;
    }
    for(int i=1;i<=Q;i++){
        q[i].op=read(),q[i].x=read(),q[i].y=read();
        if(q[i].op==2){
        	if(q[i].x>q[i].y) swap(q[i].x,q[i].y);
            q[i].id=mp[make_pair(q[i].x,q[i].y)];
            vis[q[i].id]=1;
        }
    }
    int x,y,t,a,b,tot=0;
    for(int i=1;i<=n;i++) f[i]=i;
    for(int i=1;i<=m;i++){
        if(!vis[i]){
            x=e[i].x;y=e[i].y;
            a=find(x);b=find(y);
            if(a!=b){
                link(x,i+n);link(y,i+n);
                f[a]=b;tot++;
                if(tot==n-1) break;
            }
        }
    }
    for(int i=Q;i>=1;i--){
        x=q[i].x;y=q[i].y;
        if(q[i].op==1){
            split(x,y);ans[i]=val[Max[y]];
        }
        else {
            split(x,y);t=Max[y];
            if(val[q[i].id+n]<val[t]){
                cut(e[t-n].x,t);cut(e[t-n].y,t);
                link(x,q[i].id+n);link(y,q[i].id+n);
            }
        }
    }
    for(int i=1;i<=Q;i++)
        if(q[i].op==1) printf("%d\n",ans[i]);
    return 0;
}

4、[NOI2014]魔法森林

边权先按 \(b\) 排序,然后维护一个 \(a\) 的最大边权的最小值,把边权转换成点权。

\(Code\ Below:\)

// luogu-judger-enable-o2
#include <bits/stdc++.h>
using namespace std;
const int maxn=200000+10;
const int inf=0x3f3f3f3f;
int n,m,ch[maxn][2],fa[maxn],val[maxn],Max[maxn],sta[maxn],top,ans=inf;
bool rev[maxn];

struct Edge{
	int x,y,a,b;
}e[maxn];

bool cmp(Edge x,Edge y){
	return x.b<y.b;
}

inline int read(){
	register int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return (f==1)?x:-x;
}

inline void reverse(int x){
	swap(ch[x][0],ch[x][1]);
	rev[x]^=1;
}
inline void pushup(int x){
	Max[x]=x;
	if(val[Max[ch[x][0]]]>val[Max[x]]) Max[x]=Max[ch[x][0]];
	if(val[Max[ch[x][1]]]>val[Max[x]]) Max[x]=Max[ch[x][1]];
}
inline void pushdown(int x){
	if(rev[x]){
		rev[x]=0;
		if(ch[x][0]) reverse(ch[x][0]);
		if(ch[x][1]) reverse(ch[x][1]);
	}
}
inline bool nrt(int x){
	return x==ch[fa[x]][0]||x==ch[fa[x]][1];
}
inline void rotate(int x){
	int y=fa[x],z=fa[y],k=(x==ch[y][1]),u=ch[x][k^1];
	if(nrt(y)) ch[z][ch[z][1]==y]=x;
	ch[y][k]=u;ch[x][k^1]=y;
	if(u) fa[u]=y;fa[y]=x;fa[x]=z;
	pushup(y);pushup(x);
}
inline void splay(int x){
	int y,z;top=0;
	for(y=x;nrt(y);y=fa[y]) sta[++top]=y;
	pushdown(y);
	while(top) pushdown(sta[top--]);
	while(nrt(x)){
		y=fa[x],z=fa[y];
		if(nrt(y)) rotate((x==ch[y][1])^(y==ch[z][1])?x:y);
		rotate(x);
	}
}
inline void access(int x){
	int y=0;
	for(;x;y=x,x=fa[x])
		splay(x),ch[x][1]=y,pushup(x);
}
inline int findroot(int x){
	access(x),splay(x);
	for(;ch[x][0];x=ch[x][0]) pushdown(x);
	return x;
}
inline void makeroot(int x){
	access(x),splay(x),reverse(x);
}
inline int split(int x,int y){
	makeroot(x),access(y),splay(y);
	return Max[y];
}
inline void link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x)
		fa[x]=y,pushup(y);
}
inline void cut(int x,int y){
	makeroot(x);
	if(findroot(y)==x&&fa[x]==y&&!ch[y][1])
		fa[x]=ch[y][0]=0,pushup(y);
}


int main()
{
	n=read(),m=read();
	for(int i=1;i<=m;i++)
		e[i].x=read(),e[i].y=read(),e[i].a=read(),e[i].b=read();
	sort(e+1,e+m+1,cmp);
	for(int i=1;i<=m;i++){
		val[i+n]=e[i].a;
		Max[i+n]=i+n;
	}
	int x,y,t;bool flag=0;
	for(int i=1;i<=m;i++){
		x=e[i].x;y=e[i].y;flag=1;
		if(findroot(x)==findroot(y)){
			t=split(x,y);
			if(val[t]>e[i].a) cut(e[t-n].x,t),cut(e[t-n].y,t);
			else flag=0;
		}
		if(flag) link(x,i+n),link(y,i+n);
		if(findroot(1)==findroot(n)) ans=min(ans,e[i].b+val[split(1,n)]);
	}
	printf("%d\n",(ans==inf)?-1:ans);
	return 0;
}
posted @ 2018-12-05 18:32  Owen_codeisking  阅读(194)  评论(0编辑  收藏  举报