题目大意:两个小伙伴A,B在耍,A给出一段长度为n的01串(未知,最大长度为1e9),B给出两个值l,r询问
区间[l,r]内1的个数为奇数还是偶数(共询问m次),A给出应答,但A得应答不一定正确。问m次应
答中A是否有在第k次(第一次出现)中给出错误应答,若有则输出数字k-1,没有则输出m。
题目分析:是一道比较巧妙的并查集题目,首先要注意的是对于给出的l和r,要进行分析得是l-1和r,因为l-r区
间的奇偶性是已给出的,那么用rel[r]^rel[l-1]就可以知道在该段区间奇偶性给出前原区间(l-r)的奇偶
性,再进行判断即可。当然判断是在l-1和r都在同一集合下才进行的,倘若不在则可进行合并,同时更
新根结点的值,我是将小的值作为根结点
需要注意得是本题数据过大,无法开数组,需要进行离散化操作。
符号:^(异或)-> 1^1=0 0^1=1 1^0=0 0^0=0
该题中1代表奇数,0代表偶数
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=10005;
int pre[maxn],fa[maxn],rel[maxn],cnt;
struct node
{
int l,r;
char s[10];
}ax[5005];
int find1(int x)
{
if(x==fa[x])
return x;
int temp=fa[x];
fa[x]=find1(fa[x]);
rel[x]=rel[x]^rel[temp];
return fa[x];
}
int getpos(int x)
{
return lower_bound(pre,pre+cnt,x)-pre;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
cnt=0;
int flag=-1;
for(int i=0;i<=10005;i++)
fa[i]=i,rel[i]=0;
int m;
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d%d%s",&ax[i].l,&ax[i].r,&ax[i].s);
ax[i].l--;
pre[cnt++]=ax[i].l;//离散化操作
pre[cnt++]=ax[i].r;//离散化操作
}
sort(pre,pre+cnt);//离散化操作
int size=unique(pre,pre+cnt)-pre;//离散化操作(去重)
for(int i=0;i<m;i++)
{
int x=getpos(ax[i].l),y=getpos(ax[i].r);
if(flag==-1)
{
int fx=find1(x),fy=find1(y);
if(fx==fy)
{
if(rel[x]^rel[y]==0&&ax[i].s[0]=='o')
flag=i;
if(rel[x]^rel[y]==1&&ax[i].s[0]=='e')
flag=i;
}
else
{
if(fx>fy)
{
fa[fx]=fy;
if(ax[i].s[0]=='o')
rel[fx]=rel[x]^rel[y]^1;
else
rel[fx]=rel[x]^rel[y]^0;
}
else
{
fa[fy]=fx;
if(ax[i].s[0]=='e')
rel[fy]=rel[x]^rel[y]^0;
else
rel[fy]=rel[x]^rel[y]^1;
}
}
// cout<<rel[x]<<" "<<rel[y]<<endl;
}
if(flag!=-1)
break;
}
printf("%d\n",flag==-1?m:flag);
}
return 0;
}