模板题
find 函数不仅有找祖宗的功能,还把这个查找路径上所有节点直接变成了祖宗节点的孩子
#include<iostream>
using namespace std;
const int N=100010;
int p[N];//定义多个集合
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
/*
经上述可以发现,每个集合中只有祖宗节点的p[x]值等于他自己,即:
p[x]=x;
*/
return p[x];
//找到了便返回祖宗节点的值
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) p[i]=i;
while(m--)
{
char op[2];
int a,b;
scanf("%s%d%d",op,&a,&b);
if(*op=='M') p[find(a)]=find(b);//集合合并操作
else
if(find(a)==find(b))
//如果祖宗节点一样,就输出yes
printf("Yes\n");
else
printf("No\n");
}
return 0;
}
字符串,用map变形的题目
#include<bits/stdc++.h>
using namespace std;
const int N=2e4+10;;
int p[N];//定义多个集合
map<string,int>mmp;
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
string s;cin>>s;
mmp[s]=i;
}
for(int i=1;i<=n;i++) p[i]=i;
while(m--)
{
string s1,s2;
cin>>s1>>s2;
p[find(mmp[s1])]=find(mmp[s2]);//集合合并操作
}
int k;
cin>>k;
while(k--)
{
string s1,s2;
cin>>s1>>s2;
if(find(mmp[s1])==find(mmp[s2]))cout<<"Yes."<<endl;
else cout<<"No."<<endl;
}
return 0;
}
在最后寻找不同并查集个数的地方升级了
#include<bits/stdc++.h>
using namespace std;
const int N=2e7+10;;
int p[N];//定义多个集合
int find(int x)
{
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n*m;i++) p[i]=i;
int t;cin>>t;
while(t--)
{
int s1,s2;
cin>>s1>>s2;
p[find(s1)]=find(s2);//集合合并操作
}
int ans=0;
for(int i=1;i<=n*m;i++)
{
if(p[i]==i)ans++;
}
cout<<ans;
// vector<int>a(n*m+1);
// for(int i=1;i<=n*m;i++)
// {
// a.push_back(find(i));
// }
// sort(a.begin(),a.end());
// a.erase(unique(a.begin(),a.end()),a.end());
// cout<<a.size()-1<<endl;//去除0
return 0;
}
这里的并查集直接将相交的球合并起来了,最后判断上下表面的球所在的集合有没有相连
#include<bits/stdc++.h>
using namespace std;//不加本代码爆零
const int N=100001;
typedef long long LL;
int p[1001];//并查集
LL x[N],y[N],z[N];
int find(int x)
{
//如果x的指向不是
if(x!=p[x])p[x]=find(p[x]);
return p[x];
}
//两点距离公式,注意这里算的是距离平方。
LL dis(long long x,long long y,long long z,long long x1,long long y1,long long z1){
return (x-x1)*(x-x1)+(y-y1)*(y-y1)+(z-z1)*(z-z1);
}
//分别记录 与上表面相交的洞的编号和与下表面相交的洞的编号
int cnt_up[N],cnt_down[N];
int main()
{
int T;
cin>>T;
LL n,h,r;
while(T--)
{
cin>>n>>h>>r;
int tot1=0;
int tot2=0;
//并查集初始化
for(int i=1;i<=n;i++)p[i]=i;
for(int i=1;i<=n;i++)
{
cin>>x[i]>>y[i]>>z[i];
//判断这个点是否与上表面相交
if(z[i]+r>=h)
{
//记录与上表面相交的序号
cnt_up[++tot1]=i;
}
//判断这个点是否与下表面相交
if(z[i]-r<=0)
{
//记录与上表面相交的序号
cnt_down[++tot2]=i;
}
//枚举之前的洞是否与当前的洞相交,相交的话并查集合并
for(int k=1;k<=i;k++)
{
//判断边界
//if ((x[i]-x[k])*(x[i]-x[k])+(y[i]-y[k])*(y[i]-y[k])>4*r*r) continue;
if(dis(x[i],y[i],z[i],x[k],y[k],z[k])<=4*r*r)
{
if(find(i)!=find(k))//前提条件
{
//并查集的合并
p[find(i)]=find(k);
}
}
}
}
int ans=0;
//循环遍历
for(int i=1;i<=tot1;i++)
{
for(int j=1;j<=tot2;j++)
{
if(find(cnt_up[i])==find(cnt_down[j]))
{
ans=1;
break;
}
}
if(ans==1)break;
}
if(ans==1)cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
return 0;
}