列表

详情


NC22578. 动态连通块

描述

小T有n个点,每个点可能是黑色的,可能是白色的。
小T对这张图的定义了白连通块和黑连通块:
白连通块:图中一个点集V,若满足所有点都是白点,并且V中任意两点都可以只经过V中的点互相到达,则称V中的点构成了一个白连通块。
黑连通块:类似白连通块的定义。
小T对这n个点m次操作。
1、在两个点之间连一条边。
2、询问白(黑)连通块个数。
3、给出x,y两个点,保证同色(为了方便描述,x,y都是白点,黑色同理)。询问存在多少个黑点,将它改变颜色后,x,y所在的白连通块会合并为一个。如果x,y已经在一个白连通块内了,输出-1。(注意:这里不会对点的颜色改变,只统计个数)


输入描述

第一行两个整数n,m,分别表示点的个数和操作的个数。
第二行n个整数,第i个整数描述第i个点的颜色,0表示白色,1表示黑色。
接下来m行,每行包含2个或者3个整数,描述三种操作。
操作1:1,x,y,表示在x,y之间加入一条边。
操作2:2,x,若x=0,询问白连通块的个数,否则询问黑连通块的个数。
操作3:3,x,y,表示第三种操作。

输出描述

对于询问操作,输出一个整数。

示例1

输入:

6 7
0 1 0 0 0 1
1 3 2
1 2 4
3 3 4
1 1 3
2 0
3 1 4
3 1 3

输出:

1
3
1
-1

说明:

第一次询问:2号点变成白色后,3,4所在的白连通块合并为一个。
第二次询问:白连通块的个数为3,分别是{1,2},{3},{4}。
第三次询问:2号点变成白色后,1,4所在的白连通块合并为一个。
第四次询问:1,3已经是同一个白连通块了,输出-1。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 458ms, 内存消耗: 143608K, 提交时间: 2019-02-09 11:05:10

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e4+10;
int n,m,ans1,ans0,tot0,tot1;
bool mp[maxn];
int tot;
int fa[maxn];
bitset<maxn>f[maxn],g;
int find(int x)
{
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}
void add(int u,int v)
{
	if(mp[u]==mp[v]){
		u=find(u);
		v=find(v);
		if(u!=v){
			fa[u]=v;
			f[v]|=f[u];
			if(mp[u]) --ans1;
			else --ans0;
		}
	}
	else{
		int t1=find(u),t2=find(v);
		f[t1].set(v);
		f[t2].set(u);
	}
}
void query1(int x)
{
	printf("%d\n",x==0?ans0:ans1);
}
void query2(int u,int v)
{
	u=find(u),v=find(v);
	if(u==v){
		printf("-1\n");
		return;
	}
	g=f[u]&f[v];
	printf("%d\n",g.count());
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;++i) {
		cin>>mp[i];	
		fa[i]=i;
		if(mp[i]) ++ans1,++tot1;
		else ++ans0,++tot0;
	}
	int s,x,y;
	while(m--)
	{
		cin>>s;
		if(s==1){
			cin>>x>>y;
			add(x,y);
		}
		else if(s==2){
			cin>>x;
			query1(x);
		}
		else{
			cin>>x>>y;
			query2(x,y);
		}
	}
	return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 233ms, 内存消耗: 143828K, 提交时间: 2019-03-20 03:38:25

#include<bits/stdc++.h>
using namespace std;const int N=5e4+7;
bitset<N> bit[N];int n,m,i,j,k,num[N],col[N],fa[N],op,x,y,z;
int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int main(){
	for(scanf("%d%d",&n,&m),i=1;i<=n;++i)fa[i]=i,scanf("%d",col+i),num[col[i]]++;
	for(;m--;){
		scanf("%d",&op);
		if(op==1){
			scanf("%d%d",&x,&y);
			if(col[x]==col[y]){
				if(find(x)!=find(y))bit[find(y)]|=bit[find(x)],fa[find(x)]=find(y),num[col[x]]--;
			}
			else bit[find(x)][y]=bit[find(y)][x]=1;
		}
		if(op==2)scanf("%d",&x),printf("%d\n",num[x]);
		if(op==3)scanf("%d%d",&x,&y),printf("%d\n",find(x)==find(y)?-1:1*(bit[find(x)]&bit[find(y)]).count());
	}
}

上一题