题目大意:警察抓获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; }