bzoj2303

并查集+数学

这道题网上好像有两种解法。

这位写的很可读:http://blog.csdn.net/unicornt_/article/details/51901225

然后看完大概就懂了做法,但是实现上还有很多细小的地方。

cnt要-1,因为第一行和第一列会算两次。

数组要开四倍。

至于为什么要拆成两个点,这是因为分开考虑01.

为什么两个flag都要赋值?因为有可能根是放在列上了,就判不到了。

还需要思考一下。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1001000;
const ll mod = 1000000000;
struct dsu {
    int fa[N * 4];
    void ini(int n)
    {
        for(int i = 1; i <= n; ++i)
            fa[i] = i;
    }
    int find(int x)
    {
        return x == fa[x] ? x : fa[x] = find(fa[x]);
    }
    void connect(int x, int y)
    {
        fa[find(x)] = find(y);
    }
    bool same(int x, int y)
    {
        return find(x) == find(y);
    }
} u;
int n, m, k, s = -1;
int x[N], y[N], c[N];
ll ans;
bool flag[N * 4];
ll power(ll x, ll t)
{
    ll ret = 1;
    for(; t; t >>= 1, x = x * x % mod) if(t & 1) ret = ret * x % mod;
    return ret;
}
void solve(int s)
{
    u.ini(2 * n + 2 * m + 100);
    u.connect(2, 2 + 2 * n);
    u.connect(3, 2 + 2 * n + 1);
    for(int i = 1; i <= k; ++i)
    {
        int p = 0;
        if(x[i] % 2 == 0 && y[i] % 2 == 0) p = 1;
        p = p ^ c[i] ^ s;
        if(p)
        {
            u.connect(x[i] * 2, y[i] * 2 + 1 + 2 * n);
            u.connect(x[i] * 2 + 1, y[i] * 2 + 2 * n);
        }
        else
        {
            u.connect(x[i] * 2, y[i] * 2 + 2 * n);
            u.connect(x[i] * 2 + 1, y[i] * 2 + 2 * n + 1);
        }
    }
    int cnt = 0;
    memset(flag, 0, sizeof(flag));
    for(int i = 1; i <= n; ++i)
    {
        if(u.same(i * 2, i * 2 + 1))
            return;
        if(!flag[u.find(i * 2)])
        {
            flag[u.find(i * 2)] = flag[u.find(i * 2 + 1)] = 1;
            ++cnt;
        }
    }
    for(int i = 1; i <= m; ++i)
    {
        if(u.same(i * 2 + 2 * n, i * 2 + 2 * n + 1))
            return;
        if(!flag[u.find(i * 2 + 2 * n)])
        {
            flag[u.find(i * 2 + 2 * n)] = flag[u.find(i * 2 + 2 * n + 1)] = 1;
            ++cnt;
        }
    }
    ans = (ans + power(2ll, cnt - 1)) % mod;
}
int main()
{
    scanf("%d%d%d", &n, &m, &k);
    for(int i = 1; i <= k; ++i)
    {
        scanf("%d%d%d", &x[i], &y[i], &c[i]);
        if(x[i] == 1 && y[i] == 1) s = c[i];
    }
    if(s != 1) solve(0);
    if(s != 0) solve(1);
    printf("%lld\n", ans);
    return 0;
}
View Code

 

posted @ 2017-06-28 19:47  19992147  阅读(149)  评论(0编辑  收藏  举报