zoukankan      html  css  js  c++  java
  • [学习笔记]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
    ",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
    ");
    			else printf("no
    ");
    		}
    		if(opt[0]=='p'){
    			splay(x),a[x]=y,pushup(x);
    		}
    		if(opt[0]=='e'){
    			makeroot(x);
    			if(findroot(y)!=x)
    				printf("impossible
    ");
    			else split(x,y),printf("%d
    ",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
    ",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
    ",(ans==inf)?-1:ans);
    	return 0;
    }
    
  • 相关阅读:
    封装aixos拦截器
    vue路由传参的三种基本方式
    vue里的路由钩子
    箭头函数特点
    webstorm激活码
    vue-cli2使用less
    vue-cli2使用rem适配
    XfZGkvBaeh
    python解析excel中图片+提取图片
    python解析谷歌在线表格链接,转化为数组形式,图片转化为链接
  • 原文地址:https://www.cnblogs.com/owencodeisking/p/10072620.html
Copyright © 2011-2022 走看看