并查集的一个好题目,因为石头剪刀布的三角关系,我们可以用0表示两个同类,1表示被它的父亲克制,2表示克制它的父亲,那么一个节点和爷爷节点的关系就变成了,(re[x] + re[pre[x] ]) % 3 ,因为并查集带压缩路径,所以最后join时,最多存在一个四边形的关系,讨论x和y的根节点是否相同即可。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int pre[maxn],re[maxn];
int n,m,opt,x,y,cnt,tag;
void init(int n){
for (int i=0; i<=n; i++) {
pre[i] = i;
}
}
int find(int x){
if (pre[x] == x) return x;
int fx = find(pre[x]);
re[x] = (re[pre[x]]+re[x]) % 3;
pre[x] = fx;
return fx;
}
void join(int x,int y,int opt){
int fx = find(x),fy = find(y);
if (opt == 1) opt--;
if (fx != fy){
pre[fx] = fy;
re[fx] = ((opt + re[y]) % 3 + (3 - re[x]) % 3) % 3;
}else{
if (opt != (re[x] + (3 - re[y]) % 3) % 3 && tag != 1){
cout << cnt << endl; tag = 1;
}
}
}
int main(){
cin >> n >> m;
init(n);
for (int i=0; i<m; i++) {
scanf("%d%d%d",&opt,&x,&y);
cnt++;
if (opt == 1){
join(x, y, opt);
}else if (opt == 2){
join(x, y, opt);
}
if(cnt == 3) cnt = 0;
// cout << re[x] << endl;
}
if (!tag) cout << -1 << endl;
return 0;
}