并查集模板
int n,dad[N],sizee[N];//sizee数组规定只有祖宗结点是有效值
//初始化所有集合
void Init(){for(int i=1;i<=n;i++){dad[i]=i;sizee[i]=1;}return ;
}
//查找a的祖宗节点
int Find(int a){if(dad[a]!=a) dad[a]=Find(dad[a]);//每个集合中只有祖宗节点的值等于自身的值return dad[a];
}
//将a和b的两个数所在的集合合并
void Merge(int a,int b){if(Find(a)==Find(b)) return ;//特判a,b本身就在同一个集合之中//先更新sizee数组再合并sizee[Find(b)]+=sizee[Find(a)];dad[Find(a)]=Find(b);return ;
}
//判断a,b是否在同一个集合之中
bool Check(int a,int b){if(Find(a)==Find(b)) return true;else return false;
}
//统计a所在集合的元素个数
int Count(int a){return sizee[Find(a)];
}
AcWing 528. 奶酪
暴力+并查集:
#include<iostream>
#include<cmath>
using namespace std;
const int N=1e3+5;
int T,n,h,r,dad[N];
struct point{int px,py,pz;
}p[N];
int find(int a){if(dad[a]!=a) dad[a]=find(dad[a]);return dad[a];
}
void merge(int a,int b){if(find(a)==find(b)) return ;else dad[find(a)]=find(b);
}
bool query(int a,int b){if(find(a)==find(b)) return true;else return false;
}
int main(){cin>>T;while(T--){cin>>n>>h>>r;for(int i=1;i<=n;i++){cin>>p[i].px>>p[i].py>>p[i].pz;dad[i]=i;}for(int i=1;i<=n;i++){for(int j=1;j<=n;j++){if(i!=j){double d=sqrt(pow(p[i].px-p[j].px,2)+pow(p[i].py-p[j].py,2)+pow(p[i].pz-p[j].pz,2));if(d<=2*r){merge(i,j);}}}}int flag=0;for(int i=1;i<=n;i++){if(p[i].pz<=r){for(int j=1;j<=n;j++){if(p[j].pz>=h-r){if(query(i,j)) {flag=1;break;}}}}}if(flag==0) cout<<"No"<<endl;else cout<<"Yes"<<endl;}return 0;
}
AcWing 836. 合并集合
#include<iostream>
using namespace std;
const int N=1e5+5;
int n,m,dad[N];
void init(){for(int i=1;i<=n;i++) dad[i]=i;return ;
}
int find(int a){if(dad[a]!=a) dad[a]=find(dad[a]);return dad[a];
}
void merge(int a,int b){if(find(a)==find(b)) return ;else dad[find(a)]=find(b);return ;
}
void query(int a,int b){if(find(a)==find(b)) cout<<"Yes"<<endl;else cout<<"No"<<endl;return ;
}
int main(){cin>>n>>m;init();while(m--){char ch;int a,b;cin>>ch>>a>>b;if(ch=='M') merge(a,b);else query(a,b);}return 0;
}
AcWing 837. 连通块中点的数量
注意这里先改变集合的数量,再改变集合的祖宗
sizee[find(b)]+=sizee[find(a)];
dad[find(a)]=find(b);
#include<iostream>
using namespace std;
const int N=1e5+5;
int n,m,dad[N],sizee[N];
void init(){for(int i=1;i<=n;i++) dad[i]=i,sizee[i]=1;return ;
}
int find(int a){if(dad[a]!=a) dad[a]=find(dad[a]);return dad[a];
}
void merge(int a,int b){if(find(a)==find(b)) return ;else{//注意这里先改变集合的数量,再改变集合的祖宗sizee[find(b)]+=sizee[find(a)];dad[find(a)]=find(b);return ;}
}
void query(int a,int b){if(find(a)==find(b)) cout<<"Yes"<<endl;else cout<<"No"<<endl;return ;
}
int count(int a){return sizee[find(a)];
}
int main(){cin>>n>>m;init();while(m--){string s;cin>>s;if(s=="C"){int a,b;cin>>a>>b;merge(a,b);}else if(s=="Q1"){int a,b;cin>>a>>b;query(a,b);}else{int a;cin>>a;cout<<count(a)<<endl;}}return 0;
}
AcWing 2069. 网络分析(第十一届省赛)
暴力+并查集(超时未AC 70points):
#include<iostream>
using namespace std;
const int N=1e4+5;
int n,m,dad[N],sizee[N];
void init(){for(int i=1;i<=n;i++) dad[i]=i;
}
int find(int a){if(dad[a]!=a) dad[a]=find(dad[a]);return dad[a];
}
void merge(int a,int b){if(find(a)==find(b)) return ;else dad[find(a)]=find(b);
}
bool query(int a,int b){if(find(a)==find(b)) return true;else return false;
}
void count(int a,int t){for(int i=1;i<=n;i++){if(find(i)==find(a)){sizee[i]+=t;}}
}
int main(){cin>>n>>m;init();while(m--){int x,y,z;cin>>x>>y>>z;if(x==1) merge(y,z);else count(y,z);}for(int i=1;i<=n;i++) cout<<sizee[i]<<" ";return 0;
}
优化树上差分+并查集:
#include<iostream>
using namespace std;
const int N=1e4+5;
int n,m,dad[N],ans[N];
void init(){for(int i=1;i<=n;i++) dad[i]=i;
}
int find(int a){//路径压缩之后,父节点就是根节点//因此两种情况直接返回:一个是根节点本身,另一个是节点和他的父结点if(dad[a]==a||dad[dad[a]]==dad[a]) return dad[a];int temp=find(dad[a]);ans[a]+=ans[dad[a]];dad[a]=temp;return temp;
}
void merge(int a,int b){if(find(a)==find(b)) return ;else{ans[find(a)]-=ans[find(b)];//保证a中的子树节点值不变dad[find(a)]=find(b);}
}
void count(int a,int t){ans[find(a)]+=t;
}
int main(){cin>>n>>m;init();while(m--){int x,y,z;cin>>x>>y>>z;if(x==1) merge(y,z);else count(y,z);}for(int i=1;i<=n;i++){//根节点就直接输出权值if(i==find(i)) cout<<ans[i]<<" ";//每个节点的权值就等于该点的权值加上根节点的权值else cout<<ans[i]+ans[find(i)]<<" ";}return 0;
}