洛谷 P5937 奇偶游戏
闲话
虽然这题好像找不到原题了,但毋庸置疑地说这的确是并查集的好题。
分析
可以先对奇偶区间进行分析,当这个有偶数个 1 时,区间 \(1-(left-1)\) 一定与 区间 \(1-right\) 的奇偶性相同。
上面的图 \(3-4\) 为偶区间,根据分析,\(1-2\) 为奇区间。\(1-4\) 也为奇区间。
但如果填入的是个奇区间,那么 \(1-2\) 为奇区间,而 \(1-4\) 为偶区间。
知道这个性质我们就可以把奇数区间和偶数区间合并在一起,当遇到添加偶区间却遇到奇区间时就找到了矛盾。
我们可以用开二倍空间的数组分别存储奇区间和偶区间,其实分两个也行。
下见代码,注意这些(x-1)之类的都表示的是(1-(x-1))。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e5+100;//俩倍点
int a[N];
int n,q;
int fa[N];
int find(int x){
if(x==fa[x]){
return x;
}
return fa[x]=find(fa[x]);
}
void merge(int x,int y){
x=find(x);
y=find(y);
fa[y]=x;
}
int main(){
ios::sync_with_stdio(false);
cin>>n>>q;
for(int i=0;i<=N-66;i++){
fa[i]=i;
}
int cnt=0,ans=-1;
while(++cnt){
if(cnt>q){
break;
}
int x,y;
string s;
cin>>x>>y>>s;
if(s[0]=='e'){
//奇数和偶数会合并
if(find(x-1)==find(y+n)&&find(x-1+n)==find(y)){
ans=cnt;
break;
}
merge(x-1,y);//奇数
merge(x-1+n,y+n);//偶数
}
else{
//奇数与奇数,偶数与偶数会合并
if(find(x-1)==find(y)&&find(x-1+n)==find(y+n)){
ans=cnt;
break;
}
merge(x-1,y+n);//偶变奇
merge(x-1+n,y);//奇变偶
}
}
cout<<ans;
return 0;
}