给出
n
n
n个人,然后每次给出一对
x
x
x和
y
y
y关系,表示
x
x
x和
y
y
y不在同一个阵营。或者让你查询
x
x
x和
y
y
y的关系,可以是同一阵营,不同阵营或者是不确定。
并查集直接维护不易维护,这个带权多维护一个到根的距离。如果不在同一个集合里面,那么无法确定关系。否则是否同一个阵营取决了距离的奇偶性。
带权并查集在find的时候,要保存下父亲节点,然后更新完父亲节点之后。再更新当前节点的距离
d
i
s
[
c
u
r
]
=
(
d
i
s
[
c
u
r
]
+
d
i
s
[
f
a
]
)
dis[cur]=(dis[cur]+dis[fa])
dis[cur]=(dis[cur]+dis[fa])。
另外合并的时候除了要把一个根的父亲置为另外一个根,也要更新距离,这个距离可以通过矢量法来判断,
x
x
x与
y
y
y距离为
1
1
1,
x
x
x到根是
d
i
s
[
x
]
dis[x]
dis[x],
y
y
y到根是
d
i
s
[
y
]
dis[y]
dis[y],那么两根距离就是走了一条路径,其距离为
d
i
s
[
x
]
+
1
−
d
i
s
[
y
]
dis[x]+1-dis[y]
dis[x]+1−dis[y]。
#include<bits/stdc++.h>
const int N=1e5+7;
int fa[N],dis[N];
int find(int x) {
if(x==fa[x]) return x;
int t=fa[x];
fa[x]=find(fa[x]);
dis[x]=(dis[x]+dis[t])%2;
return fa[x];
}
void Union(int x,int y) {
int fx=find(x);
int fy=find(y);
fa[fy]=fx;
dis[fy]=(dis[y]+1-dis[x])%2;
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) fa[i]=i;
for(int i=1;i<=n;i++) dis[i]=0;
while(m--) {
char opt[3];
int x,y;
scanf("%s%d%d",opt,&x,&y);
if(opt[0]=='D') {
Union(x,y);
}
else if(opt[0]=='A') {
int fx=find(x);
int fy=find(y);
if(fx!=fy) puts("Not sure yet.");
else if(dis[x]^dis[y]) puts("In different gangs.");
else puts("In the same gang.");
}
}
}
return 0;
}