• BZOJ 4998 星球联盟


    题意:给一张无向图,并不断加边 ((u,v)),并询问 (u,v) 是否位于同一个双联通分量里,若位于同一双联通分量,输出这个双联通分量的 (size)

    使用并查集+LCT维护。
    有两套并查集:s1 是用来维护每个点归属哪一个强连通分量,每个点的祖先是这个强连通分量的代表节点,同时代表节点存储这个强连通分量的 (size)s2 是用来维护原始图的联通性的。
    注意加边时 ((u,v)) ,我们都是对两个点所在联通分量的代表节点进行操作。
    我们加边 ((u,v)) 时,首先若两个点所在的联通分量的代表节点本来不连通,那直接加边(指同时修改 s2 和 LCT)即可。
    若原来两个点所在的联通分量的代表节点联通,那么我们 split(u,v) ,将这条链(当然链上的点可能是一个联通分量)的所有点缩成一个点,我们把所有遍历到的点的 s1 都指向 (u) ,使 (u) 作为新联通分量的代表节点。

    #include<bits/stdc++.h>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    inline int g() { R x=0,f=1;
    	register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
    	do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
    } const int N=200010;
    int n,m,q,fa[N],ch[N][2],sz[N],stk[N],sum,cur; bool tg[N];
    struct ufs { int fa[N];
    	inline void reset(int n) {for(R i=1;i<=n;++i) fa[i]=i;}
    	inline int f(int x) {return x==fa[x]?x:fa[x]=f(fa[x]);}
    }s1,s2;
    #define ls(x) (ch[x][0])
    #define rs(x) (ch[x][1])
    #define rev(x) (swap(ls(x),rs(x)),tg[x]^=1)
    inline bool isroot(int x) {return ls(s1.f(fa[x]))!=x&&rs(s1.f(fa[x]))!=x;}
    inline void spread(int x) { if(!tg[x]) return ;	
    	if(ls(x)) rev(ls(x)); if(rs(x)) rev(rs(x)); tg[x]=0;
    }
    inline void rot(int x) {
    	R y=s1.f(fa[x]); R z=s1.f(fa[y]); R d=ch[y][1]==x;
    	if(!isroot(y)) ch[z][ch[z][1]==y]=x;
    	fa[x]=z,fa[ch[y][d]=ch[x][d^1]]=y;
    	fa[ch[x][d^1]=y]=x;
    }
    inline void Splay(int x) {
    	R y=x,z,top=0; stk[++top]=x;
    	while(!isroot(y)) stk[++top]=y=s1.f(fa[y]);
    	while(top) spread(stk[top--]);
    	while(!isroot(x)) { y=s1.f(fa[x]); z=s1.f(fa[y]);
    		if(!isroot(y)) rot((ch[z][1]==y)==(ch[y][1]==x)?y:x);
    		rot(x);
    	}
    }
    inline void acc(int x) {for(R y=0;x;x=s1.f(fa[y=x])) Splay(x),rs(x)=y;}
    inline void mrt(int x) {acc(x),Splay(x),rev(x);}
    inline void split(int x,int y) {mrt(x),acc(y),Splay(x);}
    inline void link(int x,int y) {mrt(x); fa[x]=y;}
    inline void dfs(int x) { 
    	if(x!=cur) sz[cur]+=sz[x],s1.fa[x]=cur;
    	if(ls(x)) dfs(ls(x)); if(rs(x)) dfs(rs(x));
    }
    inline void add(int x,int y) { sum=0;
    	R fx=s2.f(x),fy=s2.f(y);
    	if(fx==fy) {
    		split(x,y),cur=x,dfs(x),ls(x)=rs(x)=0,sum=sz[x];
    	} else s2.fa[fx]=fy,link(x,y);
    }
    inline void main() {
    	n=g(),m=g(),q=g();
    	for(R i=1;i<=n;++i) sz[i]=1;
    	s1.reset(n),s2.reset(n);
    	for(R i=1,u,v;i<=m;++i) u=s1.f(g()),v=s1.f(g()),add(u,v);
    	for(R i=1,u,v;i<=q;++i) {
    		u=s1.f(g()),v=s1.f(g()),add(u,v);
    		if(!sum) puts("No"); else printf("%d
    ",sum);
    	}
    }
    } signed main() {Luitaryi::main(); return 0;}
    
  • 相关阅读:
    开发环境搭建
    添加约束设置方式
    ubuntu和windows双系统启动顺序的修改
    函数指针,指针函数,数组指针,指针数组 区分
    boost
    centos7 64位如何配置网络
    MySQL数据库(主键、索引、外键、触发器...)
    几种常见字符集与字符编码
    ODBC、OLEDB应用详解
    C#事件以及EventHandler、EventArgs
  • 原文地址:https://www.cnblogs.com/Jackpei/p/11984831.html
Copyright © 2020-2023  润新知