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;
}