有点难度的并查集题目。。。
题意:
每次询问都能返回该区间内的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; }