BZOJ2303:[APIO2011]方格染色(並查集)

Description

Sam和他的妹妹Sara有一個包含n × m個方格的表格。她們想要將其的每一個方格都染成紅色或藍色。
出於我的喜愛,他們想要表格中每一個2 ×   2的方形區域都包含奇數個(1 個或 3 個)紅色方格。例如,右圖是一個合法的表格染色方案(在打印稿中,深色表明藍色,淺色表明紅色) 。
但是昨天晚上,有人已經給表格中的一些方格染上了顏色!如今Sam和Sara很是生氣。
不過,他們想要知道是否可能給剩下的方格染上顏色,使得整個表格仍然知足她們的要求。
若是可能的話,知足他們要求的染色方案數有多少呢?
ios

Input

輸入的第一行包含三個整數n, m和k,分別表明表格的行數、列數和已被染色的方格數目。 以後的k行描述已被染色的方格。
其中第 i行包含三個整數xi, yi和ci,分別表明第 i 個已被染色的方格的行編號、列編號和顏色。ci爲 1 表示方格被染成紅色,ci爲 0表示方格被染成藍色。
測試

Output

輸出一個整數,表示可能的染色方案數目 W 模 10^9獲得的值。(也就是說,若是 W大於等於10^9,則輸出 W被10^9除所得的餘數)。
對於全部的測試數據,2 ≤ n, m ≤ 106,0 ≤ k ≤ 10^6,1 ≤ xi ≤ n,1 ≤ yi ≤ m。
spa

Sample Input

3 4 3
2 2 1
1 2 0
2 3 1

Sample Output

8

Solution 

這個題真的神仙……
首先能夠發現若方案合法,相鄰四個格子的數字異或和爲1.
由這個咱們能夠從格子$(1,1)$往右下角推,而後得出一個結論,若行和列都是偶數,$1xor(1,1)xor(i,j)=(1,j)xor(i,1)$
不然$(1,1)xor(i,j)=(1,j)xor(i,1)$。
那麼對於每個給出格子,他能夠肯定該行首和該列首的兩個格子的關係。
若$(1,1)$格子未被肯定,則枚舉兩個顏色而後去作。
剩下的就能夠用加權並查集判斷是否合法了……

Code

 1 #include<iostream>
 2 #include<cstdio>
 3 #define N (200009)
 4 #define MOD (1000000000)
 5 using namespace std;
 6 
 7 int n,m,k,ans,flag[2]={1,1};
 8 int x[N],y[N],c[N],fa[N],g[N];
 9 
10 int Find(int x)
11 {
12     if (x==fa[x]) return x;
13     int f=Find(fa[x]);
14     g[x]^=g[fa[x]]; return fa[x]=f;
15 }
16 
17 int Calc()
18 {
19     for (int i=1; i<=n+m; ++i) fa[i]=i,g[i]=0;
20     fa[1+n]=1;
21     for (int i=1; i<=k; ++i)
22     {
23         int fx=Find(x[i]),fy=Find(y[i]+n);
24         int temp=g[x[i]]^g[y[i]+n]^c[i];
25         if (fx!=fy) fa[fx]=fy,g[fx]=temp;
26         else if (temp) return 0;
27     }
28     int ans=-1;
29     for (int i=1; i<=n+m; ++i)
30         if (fa[i]==i)
31         {
32             if (ans==-1) ans=1;
33             else ans<<=1;
34             if (ans>=MOD) ans-=MOD;
35         }
36     return ans;
37 }
38 
39 int main()
40 {
41     scanf("%d%d%d",&n,&m,&k);
42     for (int i=1; i<=k; ++i)
43     {
44         scanf("%d%d%d",&x[i],&y[i],&c[i]);
45         if (x[i]==1 && y[i]==1) flag[c[i]^1]=0,--k,--i;
46         else if (x[i]%2==0 && y[i]%2==0) c[i]^=1;
47     }
48     if (flag[0]) ans+=Calc();
49     if (flag[1])
50     {
51         for (int i=1; i<=k; ++i)
52             if (x[i]>1 && y[i]>1) c[i]^=1;
53         ans+=Calc();
54     }
55     if (ans>=MOD) ans-=MOD;
56     printf("%d\n",ans); 
57 }
相關文章
相關標籤/搜索