BZOJ2303 APIO2011方格染色

这题太神了

首先我们可以发现只有当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\n",ans);
63     return 0;
64 }

 

转载于:https://www.cnblogs.com/nbwzyzngyl/p/8403492.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值