洛谷P1892[BOI2003]团伙:变种并查集

题面链接

https://www.luogu.com.cn/problem/P1892

题解

  • 暴力:
    我首先想到的是邻接矩阵的乘法:把二次的敌人矩阵并入朋友矩阵,然后求出 a n s ( n , n ) = ∑ i = 1 n f r i e n d ( n , n ) i ans(n,n)=\sum_{i=1}^{n} friend(n,n)^i ans(n,n)=i=1nfriend(n,n)i
    这个ans矩阵就是所有的朋友关系邻接矩阵了。然后邻接矩阵上跑个连通分量就完了。这样n次矩阵乘法复杂度 O ( n 4 ) O(n^4) O(n4)。万万不能接受。

  • 正解并查集
    经典并查集算法。把点i拆成i和i+n两个点。如果i,j朋友,就合并i,j。敌人就分别合并i+n,j和i,j+n。这样敌人的敌人就会在同一个集合里。最后答案就是1-n中的集合总个数。复杂度θ(n+m)。

AC代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int NN=1100;
int fa[NN<<1];
int f[NN<<1];
int get_fa(int x){
	if(fa[x]==x)return x;
	return (fa[x]=get_fa(fa[x]));
}
void merg(int x,int y){
	int fax=get_fa(x);
	int fay=get_fa(y);
	if(fax!=fay){
		fa[fax]=fay;
	}
}
int main(){
	int n,m;scanf("%d%d",&n,&m);
	for(int i=1;i<=n<<1;i++)fa[i]=i;
	for(int i=1;i<=m;i++){
		int x,y;
		char s[3];
		scanf("%s%d%d",s,&x,&y);
		if(s[0]=='F'){
			merg(x,y);
		}
		else{
			merg(x+n,y);
			merg(x,y+n);
		}

	}
	for(int i=1;i<=n;i++){
		f[get_fa(i)]=1;
	}
	int ans=0;
	for(int i=1;i<=n<<1;i++)ans+=f[i];
	printf("%d\n",ans);
	return 0;
}

结果

不开O2的情况下:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值