有点难度的并查集题目。。。
题意:
每次询问都能返回该区间内的1个数的奇偶性,问这些询问从第几个开始就不正确了。
思路:(from:http://www.cnblogs.com/ltang/archive/2010/12/07/1898919.html)
hash离散化+并查集
首先我们不考虑离散化:s[x]表示(root[x],x]区间1的个数的奇偶性,0-偶数,1-奇数
每个输入区间[a,b],首先判断a-1与b的根节点是否相同
a)如果相同表示(a-1,b]之间1的个数奇偶性已知s((a-1,b])=s[a-1]^s[b],此时只需简单判断即可
b)如果不同,我们需要合并两个子树,我们将root较大的子树(例root[a])合并到root较小的子树(例root[b]),且此时s[root[a]]=s[a]^s[b]^s((a-1,b])
在路径压缩的过程中s[i]=s[i]^s[root[i]],s[root[i]]为(root[root[i]], root[i]]区间内1个数的奇偶性,例(a, b]区间1的个数为偶数,(b, c]区间1的个数为奇数,(a, c]之间1的个数显然为0^1=1奇数
代码如下:
const int M = 10005;
int hash[M], p[M], s[M];
int nextString()
{
char tmp[10];
scanf("%s", tmp);
if(strcmp(tmp,"even")==0) return 0;
return 1;
}
int hashf(int x)
{
int cur = x%M;
while(hash[cur]!=-1)
if(hash[cur]==x) return cur;
else cur = (cur+1)%M;
hash[cur] = x;
return cur;
}
int find(int x)
{
int tmp = p[x];
p[x] = (p[x]==x?x:find(p[x]));
s[x] = s[tmp]^s[x];
return p[x];
}
int main()
{
int n, m, a, b, o, flag = 0, ans;
scanf("%d%d", &n, &m);
memset(hash,-1,sizeof(hash));
for(int i = 0; i < M; ++i) p[i] = i;
for(int i = 0; i < m; ++i)
{
scanf("%d%d", &a, &b);
o = nextString();
if(flag) continue;
int pa = hashf(a-1);
int pb = hashf(b);
int x = find(pa);
int y = find(pb);
if(x==y && s[pa]^s[pb]^o) flag = 1, ans = i;
else if(x!=y)
{
if(hash[x]>hash[y]) p[x] = y, s[x] = s[pa]^s[pb]^o;
else p[y] = x, s[y] = s[pa]^s[pb]^o;
}
}
flag?printf("%d\n", ans):printf("%d\n", m);
return 0;
}