Parity game(poj1733)
题意:
有以个串,每次给出【i,j】之间的1的个数,
有m次询问,判断当前询问是否和之前的询问相冲突,冲突就break。
思路:
由于本题的区间范围有点大,所以要先离线。
- 本每次输入的左右区间依次存入一个 数组 中。
- 之后把重复的出现去掉unique(为了后面的二分查找)
- 之后就是带权并查集的基本操作,
- 本题的dis【】稍微改变一下,就可以了(本题even为0,odd为1)
- 所以find中的dis
dis[x]^=dis[f[x]];
- merge中的
f[A]=B;
dis[A]=dis[x]^dis[y]^p[i].op;
反思
- 离线的学习。
For(i,1,q)
{
int l,r;
char s[10];
scanf("%d%d%s", &l, &r, s);
p[i].l=a[++cnt]=l-1;
p[i].r=a[++cnt]=r;
p[i].op=(s[0]=='o')?1:0;
}
离线后之后直接访问第几个即可。
2. 异或运算的学习。
本题的操作和异或运算给很像
本题的路径并不是dis[A]=dis【b】- dis【a】+ x;
因为:
odd+odd=even;
odd-odd=even;
even+even=even;
even-even=even;
odd+even=odd;
odd-even=odd;
所以无关加减了,直接异或走起
AC
#include <iostream>
#include <cstdio>
#include <algorithm>
#define For(i,x,y) for(register int i=(x); i<=(y); i++)
using namespace std;
const int maxn=1e4+10;
struct point
{
int l,r;
int op;
}p[maxn];
int f[maxn<<1], dis[maxn<<1], a[maxn<<1],cnt,n,q,x;
int find(int x)
{
if(x==f[x])return x;
int root=find(f[x]);
dis[x]^=dis[f[x]];
return f[x]=root;
}
int main()
{
scanf("%d", &n);
scanf("%d", &q);
For(i,1,q)
{
int l,r;
char s[10];
scanf("%d%d%s", &l, &r, s);
p[i].l=a[++cnt]=l-1;
p[i].r=a[++cnt]=r;
p[i].op=(s[0]=='o')?1:0;
}
For(i,1,2*q)f[i]=i;
// For(i,1,n)cout<<a[i]<<endl;
int ans=0;
sort(a+1,a+1+cnt);
n=unique(a+1,a+1+cnt)-(a+1);
//cout<<n<<endl;
For(i,1,q)
{
ans=i;
//cout<<ans<<endl;
int x=lower_bound(a+1,a+1+n,p[i].l)-a-1;
int y=lower_bound(a+1,a+1+n,p[i].r)-a-1;
// cout<<x<<' '<<y<<endl;
int A=find(x);
int B=find(y);
if(A==B)
{
if(dis[x]^dis[y]!=p[i].op)
{
ans--;
break;
}
}
else
{
f[A]=B;
dis[A]=dis[x]^dis[y]^p[i].op;
}
}
cout<<ans<<endl;
return 0;
}