题:https://ac.nowcoder.com/acm/contest/5673/I
题意:给定n对点对,每次只能从点对中取出之前没有取过的点,问最多能取到多少个不同的点。
分析:将点设为图上的点,点对即为边,离散化一下数据总共的点数为m,对于图的一个连通分量,假设它的大小为x,那么若这个连通分量有环则所有数都可以取到(贡献为x),若只是一个树形结构,则对答案的贡献为x-1。
用并查集判一下有无环即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define pb push_back #define lson root<<1,l,midd #define rson root<<1|1,midd+1,r const int inf=0x3f3f3f3f; const ll INF=1e18; const int M=2e5+5; const int mod=998244353; int f[M],a[M],b[M],vis[M],tmp[M]; int Find(int x){return x==f[x]?x:f[x]=Find(f[x]);} int main(){ int T; scanf("%d",&T); for(int cas=1;cas<=T;cas++){ int n; scanf("%d",&n); for(int u,v,i=1;i<=n;i++){ scanf("%d%d",&a[i],&b[i]); tmp[i]=a[i],tmp[i+n]=b[i]; } sort(tmp+1,tmp+1+2*n); int m=unique(tmp+1,tmp+1+2*n)-tmp-1; for(int i=1;i<=m;i++) f[i]=i,vis[i]=0; for(int i=1;i<=n;i++){ int x=lower_bound(tmp+1,tmp+1+m,a[i])-tmp; int y=lower_bound(tmp+1,tmp+1+m,b[i])-tmp; int u=Find(x),v=Find(y); if(u==v){ vis[u]=1; continue; } f[u]=v; if(vis[u])vis[v]=1; } int ans=m; for(int i=1;i<=m;i++) if(f[i]==i&&!vis[i]) ans--; printf("Case #%d: %d ",cas,ans); } return 0; }