Parity game (POJ - 1733,邊帶權 || 拓展域 並查集)

一.題目鏈接:

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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章