# 题意
首先,小A写了一个由0和1组成的序列S,长度为N。
然后,小B向小A提出了M个问题。
在每个问题中,小B指定两个数 l 和 r,小A回答 S[l~r] 中有奇数个1还是偶数个1。
机智的小B发现小A有可能在撒谎。
例如,小A曾经回答过 S[1~3] 中有奇数个1, S[4~6] 中有偶数个1,现在又回答 S[1~6] 中有偶数个1,显然这是自相矛盾的。
请你帮助小B检查这M个答案,并指出在至少多少个回答之后可以确定小A一定在撒谎。
即求出一个最小的k,使得01序列S满足第1~k个回答,但不满足第1~k+1个回答。
# 题解
将每个给定的都看作是条件,同样用到前缀和,
x表示 l-1,y表示 r
1)如果有偶数个,合并xodd和yodd,xeven和yeven,说明x为奇数和y为奇数可以互相推出,x为偶和y为偶也可以互相推出。
2)如果有奇数个,那么合并xodd和yeven,xeven和yodd,说明x为奇数和y为偶数可以互相推出,x为偶和y为奇也可以互相推出。
自然满足传递性even都+N/2和odd加以区分,并且不会冲突
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=2e4+10,base=N/2; 4 unordered_map<int,int>h; 5 int fa[N]; 6 int n,m; 7 int cnt; 8 int find(int x){ 9 if(fa[x]!=x) fa[x]=find(fa[x]); 10 return fa[x]; 11 } 12 int get(int x) { 13 if (h[x] == 0) h[x] = ++cnt; 14 return h[x]; 15 } 16 int main(){ 17 cin>>n>>m; 18 for(int i=0;i<=N;i++) 19 fa[i]=i; 20 21 for(int i=1;i<=m;i++){ 22 int l,r; 23 string op; 24 cin>>l>>r>>op; 25 l=get(l-1),r=get(r); 26 27 int x_even=l+base,x_odd=l; 28 int y_even=r+base,y_odd=r; 29 if(op == "even"){ 30 if(find(x_odd)==find(y_even)) { 31 cout<< i - 1<<endl; 32 return 0; 33 } 34 fa[find(x_even)]=find(y_even); 35 fa[find(x_odd)]=find(y_odd); 36 } 37 else { 38 if(find(x_odd)==find(y_odd)){ 39 cout<<i-1<<endl; 40 return 0; 41 } 42 fa[find(x_odd)]=find(y_even); 43 fa[find(x_even)]=find(y_odd); 44 } 45 } 46 cout<<m<<endl; 47 }