题目大意:现在给你一个n长度的串,然后n次询问及回答,在第x至第y位中元素的和 是奇数或是偶数。问从哪一次开始,下一次的回答与之前的是矛盾的。也就是找第一次与前面的条件发冲突的条件,其中 even为偶数 odd为奇数
带权并查集和dp。如果L-R的和为偶数,即可看作区间内有偶数个1,其他的都为零。如果L-R的和为奇数,即可看作区间内有奇数个1,其他的都为零。
因此我们用前缀和val[i]表示前i个数的奇偶情况。val[i]=0和1分别对应前i个数的和为偶数和奇数的情况。
进行分析:
对于1-i个数,1<=j<=i,如果i-j为偶数个1,那么val[i]=val[j-1] (即同奇偶性),即val[j-1]^val[i]=0
如果i~j为奇数个1,那么val[i]!=val[j-1] (即相反奇偶性),即val[j-1]^val[i]=1
当当前区间能和之前区间组成连续区间的时候要进行合并,并且维护节点权值,因此用带权并查集。
当当前区间已经加入集合,就判断是否和之前的条件相悖
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#define LL long long
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=1e6+5;
int n,m,num,fa[maxn],val[maxn];
char inp[10];
int getfa(int x){
if(x!=fa[x]){
int t=getfa(fa[x]);
val[x]^=val[fa[x]];
return fa[x]=t;
}
return fa[x];
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++)fa[i]=i;
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d%s",&x,&y,inp);
x--;
num= inp[0]=='o';
// cout<<x<<" "<<y<<" "<<num<<"~~~~~~~~~~~~~~~~~"<<endl;
int fx=getfa(x),fy=getfa(y);
if(fx!=fy)fa[fy]=fx,val[fy]=val[y]^val[x]^num;
else if((val[x]^val[y])!=num){
printf("%d",i-1);
return 0;
}
}
puts("ORZQHQH");
}