题目链接:点击这里
#include<bits/stdc++.h>//队友指点的并查集板子
using namespace std;
typedef long long ll;
int s[300005];
int sum[300005];//花十个月时间学了个假算法
int ddd[300005];//绝了
int find(int u){
//没听过带权并查集
if(u==s[u]) return u;
return s[u]=find(s[u]);
}
int main()
{
int t;
scanf("%d",&t);
for(int uiu=1;uiu<=t;++uiu){
int n,m,ans=0;
scanf("%d%d",&n,&m);
for(int i=0;i<=n+5;++i){
s[i]=i;
ddd[i]=1;//点数
sum[i]=0;//边数
}
for(int i=0;i<m;++i){
int x,y;
scanf("%d%d",&x,&y);
int u=find(x),v=find(y);
if(u!=v){
s[v]=u;
sum[v]+=sum[u]+1;//队友指点的并查集板子
ddd[v]+=ddd[u];
}//并查集初始化
else{
sum[v]++;
}
}
for(int i=1;i<=n;++i){
if(s[i]==i){
if(sum[i]>ddd[i])
ans=ans+sum[i]-ddd[i];
}
}
printf("Case #%d: %d\n",uiu,ans);
}
return 0;
}
#include<bits/stdc++.h>//第二个做法
using namespace std;
#define ll long long
int s[300005];
int in[300005];
int sum[300005];
int ddd[300005];
int find(int u){
if(u==s[u]) return u;
return s[u]=find(s[u]);
}
void init(int n){
for(int i=0;i<=n+5;++i){
in[i]=0;
sum[i]=0;
ddd[i]=0;
}
}
int main()
{
int t;
scanf("%d",&t);
for(int uiu=1;uiu<=t;++uiu){
int n,m,ans=0;
scanf("%d%d",&n,&m);
init(n);
for(int i=0;i<=n;++i) s[i]=i;
for(int i=0;i<m;++i){
int x,y;
scanf("%d%d",&x,&y);
++in[x],++in[y];
int u=find(x),v=find(y);
if(u!=v){
s[v]=u;
}
}
for(int i=1;i<=n;++i){
sum[find(i)]+=in[i];
++ddd[find(i)];//没学过带权并查集,单凭图论知识找点数和边数
//如果把这两句改成
/*sum[s[i]]+=in[i];
++ddd[s[i]];*/
//就会WA掉,看了2个小时硬是没看出来
}
for(int i=1;i<=n;++i){
if(s[i]==i){
if(sum[i]/2-ddd[i]>0)
ans=ans+sum[i]/2-ddd[i];
}
}
printf("Case #%d: %d\n",uiu,ans);
}
return 0;
}