POJ 1733 : Parity game
题意
对于一串很长的只含有0,1的字符串,给出信息x,y ,op(op可以是even,odd),说明序号从x到y之间有even(偶数)或者odd(奇数)个1。求最早出现信息错误的行数。
分析
若x, y之间1的个数为【偶】数个, 那么[1,x) 与[1,y]中1的个数【同】奇偶性。
若x, y之间1的个数为【奇】数个, 那么[1,x) 与[1,y]中1的个数【异】奇偶性。
我们可以将其理解为若输入x, y, even, 即x, y属于同种, 反之则属于不同种。
由于题目给出的区间是闭区间[x,y],我们需要处理成[x,y+1),也可以处理成(x, y].
由于题目数据比较大,我们需要进行离散化处理,这里使用的是STL的map容器。
代码
#include <iostream>
#include <cstdio>
#include <map>
#include <string.h>
using namespace std;
const int MAXNUM = 20000 + 10;
int id[MAXNUM];
int Size[MAXNUM];
int r[MAXNUM];
// 初始化
void make_set(int n){
for(int i = 1 ; i <= n ; i++){
id[i] = i;
Size[i] = 1;
r[i] = 0;
}
}
// 查找父节点
int Find(int p) {
while (id[p] != id[id[p]]) { //如果q不是其所在子树的根节点的直接孩子
r[p] = (r[p] + r[id[p]] ) % 2;
id[p] = id[id[p]]; //对其父节点到其爷爷节点之间的路径进行压缩
}
return id[p];
}
// 合并 p ,q节点
void Union(int p, int q, int d) {
int pRoot = Find(p);
int qRoot = Find(q);
if (pRoot == qRoot) {
return;
}
id[qRoot] = pRoot;
r[qRoot] = (r[p] - r[q] + 2 + d) % 2;
}
int main(){
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int n , m;
int p , q;
int d;
char c[10];
map<int , int> mp;
int cnt = 1;
int ans = 0;
scanf("%d %d", &n , &m);
make_set(m * 2 + 10);
for(int i = 1 ; i <= m ; i++){
scanf("%d %d %s", &p, &q ,&c);
q++;
int flag = 0;
if(strstr(c,"even"))
d = 0;
else
d = 1;
// 离散化
if(!mp[p])
mp[p] = cnt++;
if(!mp[q])
mp[q] = cnt++;
if(Find(mp[p]) == Find(mp[q])){
// 不是同类
if(d == 0 && r[mp[p]] != r[mp[q]])
flag = 1;
// 如果 x 没有吃 y
if(d == 1 && (r[mp[p]] + 1) % 2 != r[mp[q]])
flag = 1;
}else{
Union(mp[p], mp[q], d);
}
if(ans == 0 && flag == 1)
ans = i;
}
if(ans == 0)
ans = m + 1;
printf("%d\n",ans - 1);
return 0;
}