题目
题解思路
因为是提示不同帮派,所以不能用普通的并查集来解决。
注意的 点就是 不同帮派的人的不同帮派就是同一个帮派的。
很容易想到带权并查集来解决,两个状态0 1 代表相同和不同帮派。
这里还有种用朴素并查集实现的种类并查集可以解决这种问题。
开两倍的空间,利用n外的数来附加n内的数的状态。
记 a b c b 相连
我们不直接让 a b 相连 ,让 a和 b+n b和 a+n相连。 c b+n c+n b相连
这时就会有路径压缩使得a和c相连了,这样说明a c有间接的关系。
AC代码
普通并查集做法
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[200010];
int find2(int x)
{
int u = x , t ;
while( a[u]!=u )
u = a[u];
while( x!= a[x])
{
t = a[x];
a[x] = u;
x = t;
}
return u;
}
void u(int x,int y)
{
int fx = find2(x);
int fy = find2(y);
if (fx != fy )
{
a[fy] = fx;
}
}
int main ()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
getchar();
for (int i = 1 ; i <= 2*n ; i++ )
a[i] = i;
while(m--)
{
char p;
int p1,p2;
scanf("%c %d %d",&p,&p1,&p2);
getchar();
if ( p == 'D')
{
u(p1,p2+n);
u(p1+n,p2);
}else
{
if ( find2(p1) == find2(p2) )
cout<<"In the same gang.\n";
else if ( find2(p1) == find2(p2+n))
cout<<"In different gangs.\n";
else
cout<<"Not sure yet.\n";
}
}
}
return 0 ;
}
带权并查集写法
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int a[100100];
int w[100100];
int find2(int x)
{
if ( x != a[x] )
{
int t = a[x];
a[x] = find2(a[x]);
w[x] = (w[x] + w[t] )%2;
}
return a[x];
}
void u(int x,int y )
{
int fx = find2(x);
int fy = find2(y);
if ( fx != fy )
{
a[fx] = fy;
w[fx] = (- w[x] + 2 + w[y] + 1)%2;
}
}
int main ()
{
int t;
scanf("%d",&t);
while(t--)
{
int n,k;
scanf("%d%d",&n,&k);
for ( int i = 1 ;i <= n ; i++ )
a[i] = i;
for ( int i = 1 ;i <= n ; i++ )
w[i] = 0;
for (int i = 1 ;i <= k ; i++ )
{
getchar();
char p;
int c,d;
scanf("%c %d %d",&p,&c,&d);
if ( p == 'D')
{
u(c,d);
}else
{
int fx = find2(c);
int fy = find2(d);
if ( fx == fy )
{
if ( 1 == (w[c]-w[d]+2)%2 )
{
cout<<"In different gangs.\n";
}else
cout<<"In the same gang.\n";
}else
{
cout<<"Not sure yet.\n";
}
}
}
}
return 0;
}