【uoj#142】【UER #5】萬聖節的南瓜燈 亂搞+並查集
阿新 • • 發佈:2018-03-31
light ros 描述 time 並查集 因此 cstring 由於 無環
題目描述
給出一張 $n\times m$ 的網格圖,兩個格子之間有一條雙向邊,當且僅當它們相鄰,即在網格圖中有一條公共邊。
特殊地,對於 $1\le x\le n?$ ,$(x,1)?$ 和 $(x,m)?$ 也視為相鄰。但對於 $1\le y\le m?$ ,$(1,y)?$ 和 $(n,y)?$ 不視為相鄰。
現在這張網格圖有 $k?$ 個格子壞掉了,你需要判斷剩下的部分是否形成一張無向無環連通圖。
$n,m\le 10^9$ ,$k\le 10^5$ 。
題解
亂搞+並查集
對於剩下的圖:點數為 $nm-k$ ,邊數大於等於 $2nm-m-4k$ 。
由於剩下的部分是一棵樹,因此有點數大於邊數,即 $nm-k>2nm-m-4k$ 。
整理得 $(n-1)·m<3k$ 。
由於 $k$ 只有 $10^5$ ,因此 $(n-1)·m$ 只有 $3\times 10^5$ 。又因為 $n\le 3$ ,因此 $nm$ 也只有 $4.5\times 10^5$ 。
經過構造後得出最大的 $nm$ 在 $n=4,m=99999$ 時取到,為 $399996$ 。
因此當滿足 $(n-1)·m<3k$ 時暴力(數組要開到 $449997$ 以上),否則輸出No即可。時間復雜度 $O(449997T)$ 。
或當滿足 $nm\le 400000$ 時暴力(數組要開到 $400000$ 以上),否則輸出No即可。時間復雜度 $O(400000T)$ 。
#include <cstdio> #include <cstring> #define pos(i , j) ((i - 1) * m + j) int v[450010] , f[450010]; int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); } int main() { int T; scanf("%d" , &T); while(T -- ) { memset(v , 0 , sizeof(v)); int n , m , k , i , j , x , y , c = 0; scanf("%d%d%d" , &n , &m , &k); if(1ll * n * m >= m + 3 * k) { while(k -- ) scanf("%*d%*d"); printf("No"); if(T) puts(""); continue; } for(i = 1 ; i <= k ; i ++ ) scanf("%d%d" , &x , &y) , v[pos(x , y)] = 1; for(i = 1 ; i <= n * m ; i ++ ) f[i] = i; for(i = 1 ; i <= n ; i ++ ) { for(j = 1 ; j <= m ; j ++ ) { if(!v[pos(i , j)]) { if(i < n && !v[pos(i + 1 , j)]) f[find(pos(i , j))] = find(pos(i + 1 , j)) , c ++ ; if(!v[pos(i , j % m + 1)]) f[find(pos(i , j))] = find(pos(i , j % m + 1)) , c ++ ; } } } if(c != n * m - k - 1) printf("No"); else { for(i = 1 ; i <= n * m ; i ++ ) if(!v[i]) x = find(i); for(i = 1 ; i <= n * m ; i ++ ) if(!v[i] && find(i) != x) break; if(i <= n * m) printf("No"); else printf("Yes"); } if(T) puts(""); } return 0; }
【uoj#142】【UER #5】萬聖節的南瓜燈 亂搞+並查集