2020牛客暑期多校训练营(第八场)I题Interesting Computer Game(并查集)
2020牛客暑期多校训练营(第八场)I题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);
}
}