这题太神了
首先我们可以发现只有当i和j都是偶数时a[1][1]^a[1][j]^a[i][1]^a[i][j]=1才满足情况,其它时都为0
所以我们可以先把i和j都为偶数的地方^1变为0
下面才是最牛逼的地方,并查集的应用在这里体现的淋漓尽致。
0表示相同 1表示不同
一开始赋初值都表示为相同
然后每次更新并查集时只要更新他到根所有的数异或起来就是他与根的关系
由于根的g一定为0,所以此时得到的还有它实际应该是多少
我们假设一种比较复杂的情况
我们只有a[1][j]^a[i][1]^a[i][j]=0才成立!
假设此时a[i][j]的值为1(题目给出)
所以当且仅当a[1][j]与a[i][1]颜色不同时才成立
假设此时i到根异或起来为1,j到根异或起来为0
也就是说i与根颜色不同,j与根颜色相同
那么我们把两根合并时两根关系应该是什么?
相同对不对!
我们又发现此时分于两树时a[1][j]^a[i][1]^a[i][j]也为0(1^0^1=0)
结果一样对不对!
仔细想想其实他是因为异或满足的三角关系
于是乎很轻松的解决了
By:大奕哥
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=2e6+5,mod=1e9; 4 typedef long long ll; 5 struct node{ 6 int x,y,z; 7 }a[N]; 8 int n,m,k,fa[N],g[N]; 9 int get(int x) 10 { 11 if(x==fa[x])return x; 12 int t=get(fa[x]); 13 g[x]^=g[fa[x]]; 14 return fa[x]=t; 15 } 16 ll calc() 17 { 18 for(int i=1;i<=m+n;++i)fa[i]=i=i,g[i]=0; 19 fa[1+n]=1; 20 for(int i=1;i<=k;++i) 21 { 22 int fx=get(a[i].x),fy=get(a[i].y+n); 23 int tmp=g[a[i].x]^g[a[i].y+n]^a[i].z; 24 if(fx!=fy){ 25 g[fx]=tmp;fa[fx]=fy; 26 } 27 else if(tmp)return 0; 28 } 29 int ans=0; 30 for(int i=1;i<=n+m;++i) 31 { 32 if(get(i)==i) 33 { 34 if(ans==0)ans=1; 35 else 36 { 37 ans<<=1;ans%=mod; 38 } 39 } 40 } 41 return ans; 42 } 43 int main() 44 { 45 scanf("%d%d%d",&n,&m,&k); 46 int flag=-1; 47 for(int i=1;i<=k;++i) 48 { 49 scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); 50 if(a[i].x+a[i].y==2){flag=a[i].z,k--,i--;continue;} 51 if(!((a[i].x|a[i].y)&1))a[i].z^=1; 52 } 53 ll ans=0; 54 if(flag==-1||flag==0)ans=calc(); 55 if(flag==-1||flag==1){ 56 for(int i=1;i<=k;++i) 57 if(a[i].x>1&&a[i].y>1) 58 a[i].z^=1; 59 ans+=calc(); 60 } 61 ans%=mod; 62 printf("%lld ",ans); 63 return 0; 64 }