题意:
一个只含有 0,1 长度为n的字符串,有m条语句 。even 表示给定区间内 1 的个数为偶数个,odd 表示给定区间内 1 的个数为奇数个。求前几条语句是正确的
思路:
只有两种状态:偶数个1,奇数个1
先将区间 [ x , y ] 转换为(x-1 , y ],区间内 1 的奇偶性就可以根据 r[y] 和 r[x-1] 确定。我们用 r[] 数组表示这个端点到它的根节点的1的奇偶(这个区间就是(i,root(i)](0代表偶,1代表奇) 对于每个输入的区间,我们查找它们的根节点是否相同 。
根节点相同时,输入为 even ,则区间内有偶数个1,所以左右端点与根节点的关系应该相同;输入为 odd,区间内有奇数个1,所以左右端点与根节点的关系应该不同。
根节点不同时,那么就是x-1与y此时不在同一个集合中,那么我们可以知道(x-1,find(x-1) ]区间和(y,find(y) ]区间1的奇偶,并且我们知道了(x-1,y]区间1的奇偶,那么就可以推算出 ( find(x-1),find(y) ] 区间的属性,进而合并两者。在合并时,根节点,r[find(y)] = (r[x]-r[y]+k+2)%2 (输入为even时,k=0,输入为odd时,k=1), 在路径压缩过程中r[i] = ( r[i]+r[root(i)] ) %2,比如(a,b]中1的个数为偶数,(b,c]中1的个数为奇数,(a,c]中1的个数显然为奇数
参考博客:https://blog.csdn.net/qq_21057881/article/details/50614554
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<sstream>
#include<cstring>
#include<bitset>
#include<cstdio>
#include<string>
#include<deque>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#define mod 1000000007
#define ls rt<<1
#define rs rt<<1|1
using namespace std;
typedef long long ll;
const int maxn = 1e4+100;
struct node
{
int l,r;
char s[10];
}q[maxn];
int a[maxn],pre[maxn],r[maxn],n;
int find(int x)
{
if(pre[x]!=x)
{
int t = pre[x];
pre[x] = find(pre[x]);
r[x] = (r[x]+r[t])%2;
//r[x] = r[x]^r[t];
}
return pre[x];
}
int main()
{
int m,ans,tot;
ans = tot = 0;
scanf("%d",&n);
scanf("%d",&m);
for(int i=0;i<m;i++)
{
scanf("%d%d %s",&q[i].l,&q[i].r,&q[i].s);
q[i].l--;
a[tot++] = q[i].l;
a[tot++] = q[i].r;
}
sort(a,a+tot);
tot = unique(a,a+tot)-a;
for(int i=0;i<=tot;i++)
{
pre[i] = i;
r[i] = 0;
}
for(int i=0;i<m;i++)
{
int x = lower_bound(a,a+tot,q[i].l)-a;
int y = lower_bound(a,a+tot,q[i].r)-a;
int rx = find(x);
int ry = find(y);
if(rx==ry)
{
if(r[x]==r[y] && q[i].s[0]=='o') //x,y到根关系相同时,区间应该有偶数个1
break;
if(r[x]!=r[y] && q[i].s[0]=='e') //x,y到根关系不相同时,区间应该有奇数个1
break;
}
else
{
if(q[i].s[0]=='o')
{
pre[ry] = rx;
r[ry] = (r[x]-r[y]+1)%2;
//r[ry] = r[x]^r[y]^1;
}
else
{
pre[ry] = rx;
r[ry] = (r[x]-r[y]+2)%2;
//r[ry] = r[x]^r[y];
}
}
ans++;
}
printf("%d\n",ans);
return 0;
}