一.题目链接:
POJ-1733
二.题目大意:
小 A 有一个 01 串,小 B 对小A进行 m 次询问,每次询问给出一个区间,小 B 则给出此区间 1 的奇偶性.
小 B 怀疑 小 A 有时会说谎(自我矛盾)
输出至少多少个回答后可以判定 小 A 在说谎.
三.分析:
如果用 sum[i] 表示 01 串的 1 的个数的前缀和.
那么在第 i 次询问中
如果 sum[l ~ r] 有偶数个 1,等价于 sum[l - 1] 与 sum[r] 的奇偶性相同.
如果 sum[l ~ r] 有奇数个 1,等价于 sum[l - 1] 与 sum[r] 的奇偶性不同.
关系的传递为:
1. 若 a 与 b 的奇偶性相同,b 与 c 的奇偶性相同,则 a 与 c 的奇偶性相同.
2. 若 a 与 b 的奇偶性相同,b 与 c 的奇偶性不同,则 a 与 c 的奇偶性不同.
3 若 a 与 b 的奇偶性不同,b 与 c 的奇偶性不同,则 a 与 c 的奇偶性相同.
另外由于 n 的数据范围过大,这里可以用离散化将区间范围缩小到 [1 ~ 2m].
为了处理上述的关系传递关系,下面有两种解法.
① 边带权:
用 d[x] 表示 x 与 fa[x] 的奇偶性,d[x] 为 0,表示 x 与 fa[x] 的奇偶性相同,反之不同.
这样在路径压缩的过程中,对 x 到 根节点上所有的边异或一遍,则可得到 d[x] 与 根节点的奇偶关系.
对于每次询问,设在离散化之后 l - 1 与 r 的值分别为 u 和 v,设 ans 为小 A 的回答.
先检查 x 与 y 的祖先是否相同.
若相同,则去验证小 A 回答的正确性.
即检查 d[u]^d[v] 是否等于 ans.
若不相同,则将 u 的祖先挂在 v 的祖先上.
现来考虑 d[fau] 的变化.
u 到 v 的路径为 u->fau, fau->fav, fav->y.
由小 A 的回答可得
ans == d[x]^d[fau]^d[y].
即 d[fau] = d[x]^d[y]^ans.
② 拓展域
将每个点分为奇数域和偶数域,即将 u 分为两个点来表示 u_odd, v_even.
若 ans == 0,则合并 u_odd 与 v_odd,u_even 与 v_even.
若 ans == 0,则合并 u_odd 与 v_even,u_odd 与 v_even.
立即推:
若 u_odd 与 v_odd 在同一集合中,则说明 u 与 v 奇偶性相同.
若 u_odd 与 v_even 在同一集合中,则说明 u 与 v 奇偶性不同.
由此可以用来检验此 ans 的真伪.
四.代码实现:
① 边带权
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long
#define ull unsigned long long
using namespace std;
const int M = (int)2e4;
const int mod = (int)1e9 + 7;
const ll inf = 0x3f3f3f3f3f3f3f3f;
char str[5];
int d[M + 5];
int fa[M + 5];
int a[M + 5], len;
struct node
{
int l, r, ans;
}query[M + 5];
void discrete()
{
sort(a + 1, a + len + 1);
len = unique(a + 1, a + len + 1) - (a + 1);
}
int find_id(int x)
{
return lower_bound(a + 1, a + len + 1, x) - a;
}
int find_fa(int x)
{
if(x == fa[x]) return x;
int root = find_fa(fa[x]);
d[x] ^= d[fa[x]];
return fa[x] = root;
}
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; ++i)
{
scanf("%d %d %s", &query[i].l, &query[i].r, str);
query[i].ans = (str[0] == 'o');
a[++len] = query[i].l - 1;
a[++len] = query[i].r;
}
discrete();
for(int i = 1; i <= len; ++i)
fa[i] = i;
int u, v, fau, fav;
for(int i = 1; i <= m; ++i)
{
u = find_id(query[i].l - 1);
v = find_id(query[i].r);
fau = find_fa(u);
fav = find_fa(v);
if(fau == fav)
{
if((d[u]^d[v]) != query[i].ans)
{
printf("%d\n", i - 1);
return 0;
}
}
else
{
fa[fau] = fav;
d[fau] = d[u]^d[v]^query[i].ans;
}
}
printf("%d\n", m);
return 0;
}
② 拓展域:
#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-6
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long
#define ull unsigned long long
using namespace std;
const int M = (int)2e4;
const int mod = (int)1e9 + 7;
const ll inf = 0x3f3f3f3f3f3f3f3f;
char str[5];
int a[M + 5], len;
int fa[M * 2 + 5];
struct node
{
int l, r, ans;
}query[M + 5];
void discrete()
{
sort(a + 1, a + len + 1);
len = unique(a + 1, a + len + 1) - (a + 1);
}
int find_id(int x)
{
return lower_bound(a + 1, a + len + 1, x) - a;
}
int find_fa(int x)
{
if(x == fa[x]) return x;
return fa[x] = find_fa(fa[x]);
}
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; ++i)
{
scanf("%d %d %s", &query[i].l, &query[i].r, str);
query[i].ans = (str[0] == 'o');
a[++len] = query[i].l - 1;
a[++len] = query[i].r;
}
discrete();
for(int i = 1; i <= len * 2; ++i)
fa[i] = i;
int u, v, u_odd, v_odd, u_even, v_even;
for(int i = 1; i <= m; ++i)
{
u = find_id(query[i].l - 1);
v = find_id(query[i].r);
u_odd = u, u_even = u + len;
v_odd = v, v_even = v + len;
if(query[i].ans == 0)
{
if((find_fa(u_odd)) == find_fa(v_even))
{
printf("%d\n", i - 1);
return 0;
}
fa[find_fa(u_odd)] = find_fa(v_odd);
fa[find_fa(u_even)] = find_fa(v_even);
}
else
{
if(find_fa(u_odd) == find_fa(v_odd))
{
printf("%d\n", i - 1);
return 0;
}
fa[find_fa(u_odd)] = find_fa(v_even);
fa[find_fa(u_even)] = find_fa(v_odd);
}
}
printf("%d\n", m);
return 0;
}