• 【刷题】BZOJ 4998 星球联盟


    Description

    在遥远的S星系中一共有N个星球,编号为1…N。其中的一些星球决定组成联盟,以方便相互间的交流。但是,组成联盟的首要条件就是交通条件。初始时,在这N个星球间有M条太空隧道。每条太空隧道连接两个星球,使得它们能够相互到达。若两个星球属于同一个联盟,则必须存在一条环形线路经过这两个星球,即两个星球间存在两条没有公共隧道的路径。为了壮大联盟的队伍,这些星球将建设P条新的太空隧道。这P条新隧道将按顺序依次建成。一条新轨道建成后,可能会使一些星球属于同一个联盟。你的任务是计算出,在一条新隧道建设完毕后,判断这条新轨道连接的两个星球是否属于同一个联盟,如果属于同一个联盟就计算出这个联盟中有多少个星球。

    Input

    第1行三个整数N,M和P,分别表示总星球数,初始时太空隧道的数目和即将建设的轨道数目。

    第2至第M+1行,每行两个整数,表示初始时的每条太空隧道连接的两个星球编号。

    第M+2行至第M+P+1行,每行两个整数,表示新建的太空隧道连接的两个星球编号。

    这些太空隧道按照输入的顺序依次建成。

    1≤N,M,P≤200000

    Output

    输出共P行。

    如果这条新的太空隧道连接的两个星球属于同一个联盟,就输出一个整数,表示这两个星球所在联盟的星球数。

    如果这条新的太空隧道连接的两个星球不属于同一个联盟,就输出"No"(不含引号)。

    Sample Input

    5 3 4
    1 2
    4 3
    4 5
    2 3
    1 3
    4 5
    2 4

    Sample Output

    No
    3
    2
    5

    HINT

    Solution

    又是一个LCT的特殊操作——维护边双
    其实就是缩点
    LCT里真正维护的是那些缩了点之后的联通块的信息,称之为天人交战,与原图中的单个节点毫无关系(除了本身是一个联通块的),它的层次高那么一层
    所以每次调用LCT的函数之前,都要先找到它所属的联通块的编号,再用这个编号在LCT里进行操作。那么每次跳节点的时候,要保证操作的节点是在天人层次,每次就跳到那个节点指向的联通块上去
    如何记录每个点所属的联通块?用一个类似并查集的东西,记录它指向的联通块
    然后在LCT外用一个真正的并查集记录两点的连通性
    对于维护联通块,如果 (u)(v) 已经联通,再要连上一条边,那肯定就有环了,也就有边双了,那这一个环里的联通块全都要缩起来,那就一个dfs,遍历环里的所有联通块,把他们都指向一个联通块就行了,同时维护题目要求的size

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define ld long double
    const int MAXN=200000+10;
    int n,m,p,fa[MAXN];
    #define lc(x) ch[(x)][0]
    #define rc(x) ch[(x)][1]
    struct LCT{
    	int ch[MAXN][2],fa[MAXN],rev[MAXN],size[MAXN],stack[MAXN],cnt,bel[MAXN];
    	inline void init()
    	{
    		for(register int i=1;i<=n;++i)bel[i]=i,size[i]=1;
    	}
    	inline int find(int x)
    	{
    		return bel[x]==x?x:bel[x]=find(bel[x]);
    	}
    	inline bool nroot(int x)
    	{
    		return lc(find(fa[x]))==x||rc(find(fa[x]))==x;
    	}
    	inline void reverse(int x)
    	{
    		std::swap(lc(x),rc(x));
    		rev[x]^=1;
    	}
    	inline void dfs(int x,int rt)
    	{
    		if(lc(x))dfs(lc(x),rt);
    		if(rc(x))dfs(rc(x),rt);
    		if(x!=rt)bel[x]=rt,size[rt]+=size[x];
    	}
    	inline void pushdown(int x)
    	{
    		if(rev[x])
    		{
    			if(lc(x))reverse(lc(x));
    			if(rc(x))reverse(rc(x));
    			rev[x]=0;
    		}
    	}
    	inline void rotate(int x)
    	{
    		int f=find(fa[x]),p=find(fa[f]),c=(rc(f)==x);
    		if(nroot(f))ch[p][rc(p)==f]=x;
    		fa[ch[f][c]=ch[x][c^1]]=f;
    		fa[ch[x][c^1]=f]=x;
    		fa[x]=p;
    	}
    	inline void splay(int x)
    	{
    		cnt=0;
    		stack[++cnt]=x;
    		for(register int i=x;nroot(i);i=find(fa[i]))stack[++cnt]=find(fa[i]);
    		while(cnt)pushdown(stack[cnt--]);
    		for(register int y=find(fa[x]);nroot(x);rotate(x),y=find(fa[x]))
    			if(nroot(y))rotate((lc(y)==x)==(lc(find(fa[y]))==y)?y:x);
    	}
    	inline void access(int x)
    	{
    		for(register int y=0;x;x=find(fa[y=x]))splay(x),rc(x)=y;
    	}
    	inline void makeroot(int x)
    	{
    		access(x);splay(x);reverse(x);
    	}
    	inline void split(int x,int y)
    	{
    		makeroot(x);access(y);splay(y);
    	}
    	inline void link(int x,int y)
    	{
    		makeroot(x);fa[x]=y;
    	}
    };
    LCT T;
    #undef lc
    #undef rc
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char c='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(c!='')putchar(c);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    inline int found(int x)
    {
    	if(fa[x]!=x)fa[x]=found(fa[x]);
    	return fa[x];
    }
    inline int add(int u,int v)
    {
    	u=T.find(u),v=T.find(v);
    	int x=found(u),y=found(v);
    	if(u==v)return T.size[v];
    	if(x!=y)
    	{
    		fa[x]=y,T.link(u,v);
    		return -1;
    	}
    	T.split(u,v);T.dfs(T.ch[v][0],v);
    	return T.size[v];
    }
    int main()
    {
    	read(n);read(m);read(p);
    	T.init();
    	for(register int i=1;i<=n;++i)fa[i]=i;
    	for(register int i=1;i<=m;++i)
    	{
    		int u,v;
    		read(u);read(v);
    		add(u,v);
    	}
    	while(p--)
    	{
    		int u,v,res;
    		read(u);read(v);
    		if(~(res=add(u,v)))write(res,'
    ');
    		else puts("No");
    	}
    	return 0;
    }
    
  • 相关阅读:
    让HTML5来为你定位(转)
    Web开发者应知的URL编码知识(转)
    Web开发:URL编码与解码(转)
    用virtualenv建立多个Python独立开发环境(转)
    使用Ajax方式POST JSON数据包(转)
    俞敏洪:我和马云就差了8个字...(转)
    HTTP返回码中301与302的区别(转)
    Postgresql 正则表达式(转)
    【双十一狂欢,一触即发!】安全圈的学习节|绝对省钱攻略
    安全运维中基线检查的自动化之ansible工具巧用
  • 原文地址:https://www.cnblogs.com/hongyj/p/8719367.html
Copyright © 2020-2023  润新知