传送门:bzoj2303
题解
由区域内出现奇数次联想到异或,再转为并查集判联通
推荐一篇题解
代码
#include<cctype>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
#define fd(x) ((x)==1?1:(m+x-1))
const int N=1e6+10,mod=1e9;
typedef long long ll;
int n,m,K,a[N],b[N];
int f[N<<2],ss,pr=-1,lim,ans;
bool vs[N<<2],c[N];
char cp;
inline void rd(int &x)
{
cp=getchar();x=0;
for(;!isdigit(cp);cp=getchar());
for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
}
int getfa(int x){return x==f[x]?x:f[x]=getfa(f[x]);}
void merge(int x,int y,int z)
{
if(z){
if(getfa(x)!=getfa(y+lim)) f[getfa(x)]=getfa(y+lim),ss--;
if(getfa(x+lim)!=getfa(y)) f[getfa(x+lim)]=getfa(y),ss--;
}
else{
if(getfa(x)!=getfa(y)) f[getfa(x)]=getfa(y),ss--;
if(getfa(x+lim)!=getfa(y+lim)) f[getfa(x+lim)]=getfa(y+lim),ss--;
}
}
inline int fp(int x,int y)
{
int re=1;
for(;y;y>>=1,x=(ll)x*x%mod)
if(y&1) re=(ll)re*x%mod;
return re;
}
inline void sol(int ty)
{
int i;lim=n+m-1;ss=lim<<1;
for(i=1;i<=ss;++i) f[i]=i;
for(i=1;i<=K;++i) if(a[i]!=1 || b[i]!=1){
if((!(a[i]&1))&&(!(b[i]&1))) merge(b[i],fd(a[i]),1^ty^c[i]);
else merge(b[i],fd(a[i]),ty^c[i]);
if(getfa(b[i])==getfa(b[i]+lim) || getfa(fd(a[i]))==getfa(fd(a[i])+lim)) return;
}
memset(vs,0,sizeof(vs));
ss--;vs[getfa(1)]=1;
for(i=1;i<=K;++i){
if(a[i]==1 && !vs[getfa(b[i])]) vs[getfa(b[i])]=1,ss--;
else if(b[i]==1 && !vs[getfa(fd(a[i]))]) vs[getfa(fd(a[i]))]=1,ss--;
}
ans+=fp(2,ss>>1);if(ans>=mod) ans-=mod;
}
int main(){
int i,x;
rd(n);rd(m);rd(K);
for(i=1;i<=K;++i){
rd(a[i]);rd(b[i]);rd(x);c[i]=x;
if(a[i]==1 && b[i]==1) pr=c[i]^1;
}
if(pr!=0) sol(0);
if(pr!=1) sol(1);
printf("%d",ans);
return 0;
}