例题一:合并集合:

1 #include<iostream> 2 3 using namespace std; 4 5 const int N=100010; 6 7 int a[N],p[N]; 8 int n,m; 9 10 int find(int x) 11 { 12 if(p[x]!=x) p[x]=find(p[x]); 13 14 return p[x]; 15 } 16 f 17 int main() 18 { 19 cin>>n>>m; 20 for(int i=1;i<=n;i++) 21 { 22 scanf("%d",&a[i]); 23 p[i]=i; 24 } 25 while(m--) 26 { 27 char op; 28 cin>>op; 29 if(op=='M') 30 { 31 int x,y; 32 cin>>x>>y; 33 if(find(x)!=find(y)) p[find(x)]=find(y); 34 35 } 36 else 37 { 38 int x,y; 39 cin>>x>>y; 40 if(find(x)==find(y)) 41 puts("Yes"); 42 else 43 puts("No"); 44 } 45 } 46 47 return 0; 48 }
例题二:用并查集维护信息

只要我们知道每个点和根节点的关系,就知道任意俩个点之间的关系。
可以用每个点到根节点的距离来表示关系: 1 (吃根节点) 2(吃1 被根节点吃) 3 (同类) mod 3 余1(吃根节点,吃余0) 余2(被根节点吃,吃余1) 余0(和根节点同类,吃余2)

距离的含义: x吃y (y到x的距离为1)
我们只能记录每一个点到根节点的距离(每次求完一次并查集都会做路劲压缩,将到父节点的距离改成到根节点的距离)
这就好比公司里每个人的等级:要判断每个人直接的等级,只需要记录每个人与领袖之间的等级就可以知道各个人直接的关系。
1 #include <iostream> 2 3 using namespace std; 4 const int N=500010; 5 int p[N],d[N]; 6 int n,m; 7 8 9 //并查集 10 int find(int x) 11 { 12 if(p[x]!=x) 13 { 14 int t=find(p[x]); 15 d[x]+=d[p[x]]; 16 p[x]=t; 17 } 18 return p[x]; 19 } 20 21 22 23 int main() 24 { 25 cin>>n>>m; 26 27 for(int i=1;i<=n;i++) p[i]=i; 28 29 int res=0; 30 31 while(m--){ 32 int t,x,y; 33 cin>>t>>x>>y; 34 35 if(x>n || y>n) 36 { 37 res++; 38 } 39 else{ 40 int px=find(x),py=find(y); //px==x的根节点 py==y的根节点 41 if(t==1) 42 { 43 if(px==py && (d[x]-d[y])%3) res++; //如果在同一颗树上且mod3余数不为0 44 else if(px!=py) //不在同一棵树上 45 { 46 p[px]=py; //将x连到y树上 47 d[px]=d[y]-d[x]; 48 } 49 50 } 51 else{ 52 if(px==py && (d[x]-d[y]-1)%3) res++; //xy在同一颗树上,且x-y%3==1 不成立 53 else if(px!=py) 54 { 55 p[px]=py; 56 d[px]=d[y]+1-d[x]; //(d[x]+?-d[y])%3==1 57 } 58 } 59 } 60 61 } 62 63 cout<<res<<endl; 64 65 return 0; 66 67 68 }
浙公网安备 33010602011771号