BZOJ 2303 方格染色

Posted on 2016-09-06 23:36  ziliuziliu  阅读(278)  评论(0编辑  收藏  举报

首先考虑四个格子异或值为1。

然后(重点)发现每个格子的值只和最上面,最左边,和(1,1)的格子的颜色有关。

枚举(1,1)的颜色,联立方程,可以将未知数减少,那么并查集可做。

最后算答案的时候,有些连通块颜色确定,有些不确定,不确定的*2即可。

这题要注意细节!其实一开始的思路最不好想。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 1000500
#define mod 1000000000
using namespace std;
struct pnt
{
    int x,y,c;
}p[maxn];
int n,m,k,fath[maxn<<1],dis[maxn<<1],val[maxn<<1],flag=-1,cnt[maxn<<1];
void reset()
{
    for (int i=1;i<=(n-1)+(m-1);i++)
    {
        fath[i]=i;
        dis[i]=0;
        val[i]=-1;
        cnt[i]=0;
    }
}
int getfather(int x)
{
    if (x==fath[x]) return fath[x];
    if (val[x]!=-1)
    {
        if ((val[fath[x]]!=-1) && (val[fath[x]]!=(val[x]^dis[x])))
            return -1;
        val[fath[x]]=val[x]^dis[x];
    }
    int ret=getfather(fath[x]);
    dis[x]^=dis[fath[x]];
    fath[x]=ret;
    return fath[x];
}
int f_pow(int a,int b)
{
    int base=a,ans=1;
    while (b)
    {
        if (b&1) ans=(ans*base)%mod;
        base=(base*base)%mod;
        b>>=1;
    }
    return ans%mod;
}
int gets(int r)
{
    int ans=1;
    if (flag==1-r) return 0;
    reset();
    for (int i=1;i<=k;i++)
    {
        if ((p[i].x==1) && (p[i].y==1))
        {
            if (p[i].c!=r) return 0;
        }
        else if ((p[i].x==1) && (p[i].y!=1)) {if ((val[n+p[i].y-2]!=p[i].c) && (val[n+p[i].y-2]!=-1)) return 0;val[n+p[i].y-2]=p[i].c;}
        else if ((p[i].x!=1) && (p[i].y==1)) {if ((val[p[i].x-1]!=p[i].c) && (val[p[i].x-1]!=-1)) return 0;val[p[i].x-1]=p[i].c;}
        else
        {
            int x=p[i].x-1,y=n+p[i].y-2;
            int f1=getfather(x),f2=getfather(y);
            if ((f1==-1) || (f2==-1)) return 0;
            if (f1==f2)
            {
                int ret=dis[x]^dis[y]^r;
                if ((p[i].x%2==0) && (p[i].y%2==0)) ret^=1;
                if (ret!=p[i].c) return 0;
            }
            else 
            {
                int ret=p[i].c^dis[x]^dis[y]^r;
                if ((p[i].x%2==0) && (p[i].y%2==0)) ret^=1;
                if ((val[f1]!=-1) && (val[f2]!=-1)) 
                {
                    if ((val[f1]^ret)!=val[f2]) return 0;
                }
                else if ((val[f1]==-1) && (val[f2]!=-1)) {fath[f1]=f2;dis[f1]=ret;}
                else if ((val[f1]!=-1) && (val[f2]==-1)) {fath[f1]=f2;dis[f1]=ret;val[f2]=val[f1]^ret;}
                else {fath[f1]=f2;dis[f1]=ret;}
            }
        }
    }
    for (int i=1;i<=(n-1)+(m-1);i++)
    {
        int ret=getfather(i);
        if (ret==-1) return 0;
        cnt[ret]++;
    }
    for (int i=1;i<=(n-1)+(m-1);i++)
    {
        if ((fath[i]==i) && (val[i]==-1))
            ans=(ans*2)%mod;
    }
    return ans%mod;
}
int main()
{ 
    scanf("%d%d%d",&n,&m,&k);
    for (int i=1;i<=k;i++)
    {
        scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].c);
        if ((p[i].x==1) && (p[i].y==1)) flag=p[i].c;
    }
    printf("%d\n",(gets(0)+gets(1))%mod);
    return 0;
}