题目链接:https://ac.nowcoder.com/acm/contest/5673/I
题目大意:
从1~n给出n组数据,每次可以选择a 或者选择b,选了之后不能在选,问最多选多少个?
题目思路:
和之前总结的一道题很像:https://blog.csdn.net/qq_43857314/article/details/107253264
注意到关联性,所以不可以贪心的去搞
考虑并查集
当一些点连同时
如果当前存在n-1条边,也就是是一棵树,你总可以使得有n-1个点被选
如果大于n-1条边,只需要再选一个点即可
因为可以不选,所以就结束了~
注意到数据范围,所以离散化一下即可
Code:
/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include <string.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pp;
const ll INF=1e17;
const int Maxn=1e6+10;
const int maxn =1e6+10;
const int mod= 998244353;
const int Mod = 1e6+7;
const int S = 1000;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
int pre[maxn];
struct node{
int x,y;
}q[maxn];
ll sz[maxn],ed[maxn];
int vis[maxn];
vector<int>v;
int Find(int x){
return pre[x] == x?x:pre[x] = Find(pre[x]);
}
int getid(ll x){
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
int main()
{
int cas = 0;
int T;scanf("%d",&T);
while(T--){
read(n);
v.clear();
for(int i=1;i<=n;i++){
scanf("%d%d",&q[i].x,&q[i].y);
v.push_back(q[i].x);
v.push_back(q[i].y);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int szt = v.size();
/// debug(szt);
printf("Case #%d: ",++cas);
for(int i=1;i<=szt;i++) pre[i] = i,sz[i] = 1,ed[i] = 0,vis[i] = 0;
for(int i=1;i<=n;i++){
int x = getid(q[i].x),y = getid(q[i].y);
int dx = Find(x),dy = Find(y);
if(dx != dy){
pre[dx] = dy;
sz[dy] += sz[dx];
ed[dy] += ed[dx]+1;
}
else ed[dx]++;
}
ll ans = 0;
for(int i=1;i<=szt;i++){
int di = Find(i);
if(!vis[di]){
vis[di] = 1;
if(ed[di]>=sz[di]) ans+=sz[di];
else ans+=sz[di]-1;
}
}
printf("%lld\n",ans);
}
return 0;
}