2020牛客暑期多校训练营(第八场)I题Interesting Computer Game(并查集)

2020牛客暑期多校训练营(第八场)I题Interesting Computer Game(并查集)

Interesting Computer Game

题意:给n个数的a,b,对于每个i可取a[i]或b[i]或不取,输出最大取出的数的集合大小。

题解:这题有点像一个dp题,想了几分钟dp,发现是不可d的,那就找规律呗,如{1 2},{2 3}答案是2,{1 2},{2 3},{3 1}答案是3,我们发现1->2->3这种只能取3减一,但它成环则可以取3,所以只要判断所有连通块是否成环与计算其大小,并查集乱搞既可。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int t,n,u[100007],v[100007],b[200007];
int fa[200007],ok[200007],siz[200007];
int fin(int p){
	if(fa[p]==p)return p;
	else{
		return fa[p]=fin(fa[p]);
	}
}

int main(){
	int o=0;
	scanf("%d",&t);
	while(t--){
		o++;
		scanf("%d",&n);
		int m=0;
		for(int i=1;i<=n;i++){
			scanf("%d%d",&u[i],&v[i]);
			b[++m]=u[i];
			b[++m]=v[i];
		}
		sort(b+1,b+1+m);
		m=unique(b+1,b+1+m)-b-1;
		for(int i=1;i<=n;++i){
			u[i]=lower_bound(b+1,b+1+m,u[i])-b;
			v[i]=lower_bound(b+1,b+1+m,v[i])-b;
		}
		for(int i=1;i<=m;i++){
			fa[i]=i;
			ok[i]=0;
			siz[i]=1;
		}
		for(int i=1;i<=n;i++){
			int f1=fin(u[i]);
			int f2=fin(v[i]);
			if(f1==f2){
				ok[f1]=1;
			}
			else{
				fa[f1]=f2;
				ok[f2]=ok[f1]=max(ok[f2],ok[f1]);
				siz[f2]+=siz[f1];
			}
		}
		int ans=0;
		for(int i=1;i<=m;i++){
			if(fin(i)!=i)continue;
			ans+=siz[fin(i)]-1;
			if(ok[fin(i)])ans++;
		}
		printf("Case #%d: %d\n",o,ans);
	}
}

posted @ 2020-08-03 22:16  ccsu_madoka  阅读(170)  评论(0编辑  收藏  举报