解法1:
- 对每个顶点x,用x表示属于A帮派,x+n表示属于B帮派(数组大小2*n)。
- 当x和y属于不同帮派时,则x+n和y属于同一个帮派,x和y+n属于同一个帮派。
三种情况:
1. 当x和y在同一集合时(即x和y所在集合根节点相同),则x和y在同一帮派。
2. 当x和y+n或x+n和y在同一集合时,则x和y不在同一帮派。
3. 其他情况(即当x和y不在同一集合时),则x和y帮派不确定。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max_n=1e5+10;
int t,n,m;
int par[Max_n*3];
int find(int x){
if(par[x]==x)return x;
return par[x]=find(par[x]);
}
void unite(int x,int y){
x=find(x);y=find(y);
if(x==y)return;
par[x]=y;
}
bool same(int x,int y){ //判断是否在同一集合
x=find(x);y=find(y);
if(x==y)return true;
return false;
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=0;i<=n*3;i++)par[i]=i;
char s[5];
int x,y;
for(int i=0;i<m;i++){
scanf("%s%d%d",s,&x,&y);
if(s[0]=='A'){
if(same(x,y))printf("In the same gang.\n");
else if(same(x,y+n)||same(x+n,y))printf("In different gangs.\n");
else printf("Not sure yet.\n");
}
else{
unite(x+n,y);
unite(x,y+n);
}
}
}
return 0;
}
解法2:
思路:对每个节点维护其到根节点的偏移量(偏移量代表和根节点的关系)。
- par[x]表示x的根节点,rel[x]表示x与根节点的偏移量。
- rel[x]=0表示x与根节点为同帮派,1表示不同帮派。
- 当x和y属于不同帮派时,合并x和y所在的集合,并更新偏移量(即与根节点的关系)。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int Max_n=1e5+10;
int t,n,m;
int par[Max_n];
int rel[Max_n];
int find(int x){ //将沿途所有结点都指向根结点,并分别更新它们与根结点的关系
if(par[x]==x)return x;
else{
int p=find(par[x]);
rel[x]=(rel[x]+rel[par[x]])%2;
return par[x]=p;
}
}
int main()
{
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
for(int i=0;i<=n;i++){
par[i]=i;
rel[i]=0;
}
char s[5];
int x,y;
for(int i=0;i<m;i++){
scanf("%s%d%d",s,&x,&y);
int fx=find(x),fy=find(y);
if(s[0]=='A'){
if(fx==fy){
if(rel[x]==rel[y])printf("In the same gang.\n");
else printf("In different gangs.\n");
}
else printf("Not sure yet.\n");
}
else { //合并x和y所在的集合,并更新偏移量(即与根节点的关系)
par[fy]=fx;
rel[fy]=(rel[x]-rel[y]+1)%2;
}
}
}
return 0;
}