正文:
对于一张图的状态,如果我们存这张图的每一个点。那么空间复杂度是 O ( n 2 ) O(n^2) O(n2),肯定不行,更不用说时间了。
不断的画图可以发现,如果我们知道了第一行,再知道第二行第一个,我们就可以推出第二行,之后如果知道第三行第一个,就可以推出第三行……也就是我们只要知道一张图的第一列和第一行,就可以知道整张图的状态。
然后我们考虑怎么把 m p [ i ] [ j ] mp[i][j] mp[i][j]的限制推到第一行和第一列上。
m p [ 1 ] [ 1 ] x o r m p [ 1 ] [ j ] x o r m p [ i ] [ 1 ] x o r m p [ i ] [ j ] = ( i m o d 2 = = 0 a n d j m o d 2 = = 0 ) mp[1][1]\ xor\ mp[1][j]\ xor\ mp[i][1]\ xor\ mp[i][j]=(i\ mod\ 2==0\ and\ j\ mod\ 2==0) mp[1][1] xor mp[1][j] xor mp[i][1] xor mp[i][j]=(i mod 2==0 and j mod 2==0)
解释:
因为每个2*2的矩阵的异或和都是1,故我们把在矩形X(左上角坐标为(1,1),右下角坐标为(i,j))内所有的2*2矩阵都异或起来,我们会发现,除了 m p [ 1 ] [ 1 ] , m p [ 1 ] [ j ] , m p [ i ] [ 1 ] , m p [ i ] [ j ] mp[1][1],mp[1][j],mp[i][1],mp[i][j] mp[1][1],mp[1][j],mp[i][1],mp[i][j],其他点都被异或了偶数次。于是我们只要知道这些矩形的数量即可知道这四个的点异或和。(只有当i为偶数且j为偶数时2*2的矩形数量才为奇数,异或和才为1)
由上式,可以知道 m p [ 1 ] [ j ] x o r m p [ 1 ] [ j ] = ( i m o d 2 = = 0 a n d j m o d 2 = = 0 ) x o r m p [ 1 ] [ 1 ] x o r m p [ i ] [ j ] mp[1][j]\ xor\ mp[1][j]=(i\ mod\ 2==0\ and\ j\ mod\ 2==0)xor\ mp[1][1]\ xor\ mp[i][j] mp[1][j] xor mp[1][j]=(i mod 2==0 and j mod 2==0)xor mp[1][1] xor mp[i][j]
于是,我们可以枚举 m p [ 1 ] [ 1 ] mp[1][1] mp[1][1],然后推出第一行和第一列之间的点的限制(相等或不等)。这个可以通过加权并查集实现,把所有有限制关系的点并到一起,通过存与根的关系来确定一个集合内两点间的关系。
注意判不合法的状态。
最后的方案数就是2^(集合的数量-1)。(因为 m p [ 1 ] [ 1 ] mp[1][1] mp[1][1]所在的集合的点的取值已经确定)
代码:
#include<cstdio>
#define M 1000005
#define P 1000000000
int n,m,K;
int X[M],Y[M],Col[M];
//1 Red 0 Blue
int fa[M<<1],d[M<<1];//1~n line n+1~n+m column
int get_fa(int x){//加权并查集
if(x==fa[x])return x;
int f=get_fa(fa[x]);
d[x]^=d[fa[x]];
fa[x]=f;
return f;
}
int Mul(int a,int b){//快速幂
int res=1;
while(b){
if(b&1)res=1ll*res*a%P;
a=1ll*a*a%P;
b>>=1;
}
return res;
}
int Solve(int op){
for(int i=1;i<=n+m;i++)fa[i]=i,d[i]=0;
fa[n+1]=1;//左上角 (1,1)既属于第一行也属于第一列
for(int i=1;i<=K;i++){
if(X[i]==1&&Y[i]==1)continue;//1,1就不用判了
int tmp=(X[i]%2==0&&Y[i]%2==0)^Col[i]^op;
int a=get_fa(X[i]),b=get_fa(Y[i]+n);
int res=d[X[i]]^d[Y[i]+n]^tmp;
if(a==b&&res)return 0;//Col[X[i]]^Col[Y[i]+n]!=tmp
//printf("@%d %d %d\n",X[i],Y[i]+n,tmp);
fa[a]=b;
d[a]^=res;
}
int cnt=0;
for(int i=1;i<=n+m;i++)if(fa[i]==i)cnt++;
return Mul(2,cnt-1);//mp[1][1]已经确定
}
int main(){
scanf("%d%d%d",&n,&m,&K);
int flag=-1;
for(int i=1;i<=K;i++)scanf("%d%d%d",&X[i],&Y[i],&Col[i]);
for(int i=1;i<=K;i++)if(X[i]==1&&Y[i]==1)flag=Col[i];//如果1,1的值已经确定
if(flag==0)printf("%d\n",Solve(0));
else if(flag==1)printf("%d\n",Solve(1));
else printf("%d\n",(Solve(0)+Solve(1))%P);
return 0;
}