题意:
在一个城市里有两个犯罪团伙,现有N个犯罪事件,你知道M条信息
输入:
第一行是一个整数,代表样例的数目
每个样例的第一行是N和M
接下啦M行,每行有以下两种可能的形式
第一种:
D a B
意思是事件A和事件B是两个不同的犯罪团伙做的
第二种
A a b
问a和b是不是同一犯罪团伙干的
解法:
并查集,做了食物链之后做这题觉得好轻松。。。
分析:
定义并查集结构parent[],relation[]
parent[i]表示i的父节点的编号
relation[i]表示其与父节点的关系
为0表示与父节点是同一犯罪团伙
为1表示与父节点是不同犯罪团伙
设在并查集中a和b的根节点分别为ra和rb
设a到ra的带权距离为la
b到rb的带权距离为lb
a到b的带权距离为lab
则a到rb的带权距离为a->b->rb即lab+lb
则有如图所示的结果
接下来上代码
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int parent[100100];
int relation[100100];
struct T
{
int num;//根节点的编号
int quan;//到达根节点的带权距离
};
T root(int i)
{
T ans;
if(parent[i]==i)
{
ans.num=i;
ans.quan=0;
return ans;
}
T tt=root(parent[i]);
parent[i]=tt.num;
relation[i]+=tt.quan;
relation[i]%=2;
ans.num=parent[i];
ans.quan=relation[i];
return ans;
}
void Merge(int lab,int a,int b)//a和b不在同一伙
{
T tempa=root(a);
T tempb=root(b);
int ra=tempa.num;
int rb=tempb.num;
int la=tempa.quan;
int lb=tempb.quan;
parent[ra]=rb;
relation[ra]=(lab+lb-la)%2;
}
int main()
{
int total;
scanf("%d",&total);
while(total--)
{
int n,m;
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
{
parent[i]=i;
relation[i]=0;//为0代表和自己是同一犯罪团伙的
}
while(m--)
{
char type;
int a,b;
cin>>type;
scanf("%d %d",&a,&b);
if(type=='A')
{
T tempa=root(a);
T tempb=root(b);
int ra=tempa.num;
int rb=tempb.num;
if(ra!=rb)
{
printf("Not sure yet.\n");
}
else
{
if(tempa.quan==tempb.quan)
{
printf("In the same gang.\n");
}
else
{
printf("In different gangs.\n");
}
}
}
if(type=='D')
{
Merge(1,a,b);
}
}
}
return 0;
}