P3631 [APIO2011]方格染色

P3631 APIO2011方格染色

异或性质+带权并查集维护
主要是异或性质, 题目要求每个(2ast2)的矩形内异或值为1
在使用(2ast2)的矩形异或的时候,考虑对于一个矩形,除了最外面一圈,内部的格子都会被异或四次,除了内部和四个顶点的格子会被异或两次,所以可以不考虑(同一个值异或两次等于不异或),只用考虑四个顶点,那么考虑矩形 ((a,b)(a,c)(b,d)(c,d))
我们可以得到
在矩形长宽均为偶数的情况 (1 = val_{a,b} igoplus val_{a,c} igoplus val_{b,d} igoplus val_{c,d})
在矩形长宽均为偶数的情况 (0 = val_{a,b} igoplus val_{a,c} igoplus val_{b,d} igoplus val_{c,d})
更进一步,对于已知两个顶点的矩形,我们可以知道剩下两个点是否相同。
那么我们令 (a = 1, b = 1) 来做此题。
然后枚举 (val_{1, 1}) 的值,就行了。

取0和取1是相反的状态,直接给K个确定点取反就行了。

注意:

        if ((!(x[i] & 1)) && (!(y[i] & 1))) {
            k[i] ^= 1;
        }

以上代码是为了统一评判标准。

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

typedef long long ll;
const ll MAXN = 1e6+10;
const ll MOD = 1e9;

ll N, M, K, x[MAXN], y[MAXN], k[MAXN], g[MAXN], fa[MAXN];

ll calc(ll);
ll find_(ll);
ll kuaisu(ll, ll);

int main() {
    scanf("%lld%lld%lld", &N, &M, &K);
    ll flag = -1;
    for (ll i = 1; i <= K; i++) {
        scanf("%lld%lld%lld", x+i, y+i, k+i);
        if ((!(x[i] & 1)) && (!(y[i] & 1))) {
            k[i] ^= 1;
        }
        if (x[i] == 1 && y[i] == 1) {
            flag = k[i];
        }
    }
    if (-1 != flag) {
        printf("%lld
", calc(flag));
    } else {
    	ll ans = calc(0);
        printf("%lld
", (ans + calc(1)) % MOD);
    }
    return 0;
}

ll calc(ll opt) {
    if (opt == 1) {
        for (ll i = 1; i <= K; i++) if (x[i] > 1 && y[i] > 1) {
            k[i] ^= 1;
        }
    }
    for (ll i = 1; i <= N + M; i++) fa[i] = i, g[i] = 0;
    fa[N+1] = 1;
    for (ll i = 1; i <= K; i++) {
        ll a = x[i], b = y[i], c = k[i];
        if (a != 1 || b != 1) {
            ll fx = find_(a), fy = find_(b+N);
            ll tp = g[a] ^ g[b + N] ^ c;
            if (fx != fy) {
                fa[fy] = fx;
                g[fy] = tp;
            } else if (tp) {
                return 0;
            }
        }
    }
    ll tot = 0;
    for (ll i = 1; i <= N + M; i++) {
        if (i == find_(i)) tot++;
    }
    return kuaisu(2, tot-1) % MOD;
}

ll kuaisu(ll n, ll tim) {
    ll ret = 1;
    while (tim) {
        if (tim & 1) {
            ret = ret * n % MOD;
        }
        tim >>= 1;
        n = n * n % MOD;
    }
    return ret;
}

ll find_(ll x) {
    ll q;
    if (fa[x] == x) q = x;
    else {
        q = find_(fa[x]);
        g[x] ^= g[fa[x]];
        fa[x] = q;
    }
    return q;
}
Yukkuri si te yi te ne
原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13667301.html