题目大意:警察抓获N个罪犯,这些罪犯只可能属于两个团伙中的其中一个,现在给出M个条件(D a b表示a和b不在同一团伙),对于每一个询问(A a b)输出a,b属于同一团伙或者不是属于同一团伙或者不能确定。
思路:并查集的应用。普通并查集相关的题目都是给出属于同一集合的元素,但是这道题是给出了属于不同集合的元素,可以维护一个opposite数组,如果x和y不属于同一集合,则将opposite[x]赋值为y。查询的时候分别判断x,y和x,opposite[y]是不是属于同一集合即可。
#include <iostream>
using namespace std;
#include <stdio.h>
#include <memory.h>
const int MAXSIZE = 500010;
int rank[MAXSIZE];
int parent[MAXSIZE];
int opposite[MAXSIZE];
int n;//集合元素,从1到n
int FindSet(int x) {
if (x!=parent[x])
parent[x]=FindSet(parent[x]);
return parent[x];
}
void Union(int root1, int root2) {
int x=FindSet(root1),y=FindSet(root2);
if (x==y)
return;
if (rank[x]>rank[y])
parent[y]=x;
else {
parent[x]=y;
if (rank[x]==rank[y])
++rank[y];
}
}
void Initialization() {
int i;
memset(rank,0,sizeof(rank));
memset(opposite,0,sizeof(opposite));
for (i=1;i<=n;i++) {
parent[i]=i;
}
}
int main()
{
int t,m,i,j;
int x,y;
char c;
scanf("%d",&t);
while (t--) {
scanf("%d%d",&n,&m);
Initialization();
for (i=0;i<m;i++) {
getchar();
scanf("%c%d%d",&c,&x,&y);
if (c=='D') {
if (opposite[x]==0&&opposite[y]==0) {
opposite[x]=y;
opposite[y]=x;
}
else if (opposite[x]==0) {
opposite[x]=y;
Union(x,opposite[y]);
}
else if (opposite[y]==0) {
opposite[y]=x;
Union(y,opposite[x]);
}
else {
Union(x,opposite[y]);
Union(y,opposite[x]);
}
}
else {
if (FindSet(x)==FindSet(y))
printf("In the same gang.\n");
else if (FindSet(x)==FindSet(opposite[y]))
printf("In different gangs.\n");
else
printf("Not sure yet.\n");
}
}
}
return 0;
}