一.題目鏈接:
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;
}