并查集
并查集
用一个索引代表父节点,如果根一样就是一个集合。查找的时候使用路径压缩提升效率。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
int P[100100];
int findroot(int x){
if(P[x] != x) P[x]=findroot(P[x]);//这里路径压缩提升了效率,直接把P[x]更新为上一个,不用反复找了!
return P[x];
}
void merge(int a, int b){
//找到根
int roota, rootb;
roota = findroot(a);
rootb = findroot(b);
if(roota!=rootb){
P[roota] = rootb;//把a的根换成b的根,如果是同一个集合就不管了
}
}
void query(int a, int b){
int roota, rootb;
roota = findroot(a);
rootb = findroot(b);
if(roota!=rootb)cout << "No" << endl;
else cout << "Yes" << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,m;
cin >> n >> m;
for (int i = 0; i < n+1; i ++ ){
P[i]=i;//初始化指向自己的是根
}
int a,b;
char op;
while (m -- ){
cin >> op >> a >> b;
if(op=='M')merge(a,b);
else if(op=='Q')query(a,b);
}
return 0;
}
联通块的数量
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int P[100100];
int n;
int s[100100]={0};
int find(int a){
if(P[a]!=a) P[a]=find(P[a]);
return P[a];
}
void connect(int a, int b){
if(a==b)return;
int roota = find(a);
int rootb = find(b);
if(roota!=rootb){P[roota]=rootb;s[rootb]+=s[roota];}//将a的连通量加到b的
}
void queryc(int a, int b){
int roota = find(a);
int rootb = find(b);
if(roota==rootb)cout << "Yes" << endl;
else cout << "No" << endl;
}
void queryn(int a){
int roota = find(a);
//for (int i = 0; i < n+1; i ++ ){
// if(find(P[i])==roota)c++;
//}//这样太慢了直接维护一个size集合会更快!
cout << s[roota] << endl;//直接输出s数量
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int m;
cin >> n >> m;
for (int i = 0; i < n+1; i ++ ){
P[i]=i;//指向自己表示是根
s[i] = 1;
}
string op;
int a,b;
while (m -- ){
cin >> op;
if(op=="C"){
cin >> a >> b;
connect(a,b);
}
else if(op=="Q1"){
cin >> a >> b;
queryc(a,b);
}
else if(op=="Q2"){
cin >> a;
queryn(a);
}
}
return 0;
}
食物链
使用带权并查集,使用向量思维!把每个节点看成向量加减。
#include <iostream>
#include <cstring>
#include <algorithm>
//带权并查集,向量思维
using namespace std;
int P[100100];
int V[100100];
int find(int a){
int ofather=0;
if(P[a]!=a){
ofather=P[a];
P[a] = find(P[a]);
V[a] = (V[ofather] + V[a])%3;
}
return P[a];
}
void same(int a,int b){
int roota=find(a);
int rootb=find(b);
if(roota!=rootb){
P[roota] = rootb;
V[roota] = (V[b] - V[a] + 3)%3;//只需更新roota的值其他是find处理
}
}
void eat(int a, int b){
int roota=find(a);
int rootb=find(b);
if(roota!=rootb){
P[roota] = rootb;
V[roota] = (V[b]-V[a]+1+3)%3;//只需更新roota的值其他是find处理
}
}
int queryconn(int a, int b){
int roota=find(a);
int rootb=find(b);
return roota==rootb;
}
int query(int a,int b){
return (V[a]-V[b]+3)%3;//返回0说明没有eat关系
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n,k;
cin >> n >> k;
for (int i = 0; i < n+1; i ++ ){
P[i]=i;
}
int c=0;
int op,a,b;
while (k -- ){
cin >> op >> a >> b;
if(a>n||b>n){c++;continue;}
if(op==2&&a==b){c++;continue;}
if(op==1){
if(queryconn(a,b)&&query(a,b)!=0){c++;continue;}//不是0不是同类关系
same(a,b);
}
else if(op==2){
if(queryconn(a,b)&&query(a,b)!=1){c++;continue;}//不是1不是吃的关系
eat(a,b);
}
}
cout<< c<<endl;
return 0;
}