解析
看起来很不码农但写起来其实还行的一道题。
主要也是因为我贺题解把所有的雷都避过去了
首先一个比较显然的结论是:通过堵角上的,答案不超过2。
所以本题只要把答案是-1,0,1,2的情况判出来即可。
-1是只有一个空位或只有两个相邻空位。
0是原图不连通。
1是原图存在割点。
其他都是2。
做完了?太天真了。
n,m≤109n,m\le 10^9n,m≤109
那咋办?
注意到,c≤105c\le 10^5c≤105,这张图非常稀疏,在空网格上暴力tarjan看起来非常的蠢。
那怎么办?
我们尝试对于每个蛐蛐,提取出它周围的格子,这样的节点数就变成了 O(c)O(c)O(c) 级别。(感觉有些像华容道那个题)
然后在新的图上tarjan就好了。
还要注意亿点点坑点:
- 提出的“周围一圈”应该是 5×55\times 55×5 而不是 3×33\times 33×3,同时只有距离最近蛐蛐曼哈顿距离为1的点是割点才算割点。
- 判联通的时候要把8联通的蛐蛐全找出来一起判。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;const int N=1e5+100;const int mod=1333331;
const double inf=1e9;
inline ll read(){ll x(0),f(1);char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}int n,m,c;
bool flag=0;struct node{int to,nxt;
}p[N*25*4*2];
int fi[N*25],cnt;
inline void addline(int x,int y){p[++cnt]=(node){y,fi[x]};fi[x]=cnt;
}struct Hash{node p[N*25];int fi[mod+1],tot,cnt;ll key[N*25];int id[N*25];void ins(int x,int y,int Id){ll w=1ll*x*(m+1)+y,o=w%mod;++tot;id[tot]=Id;key[tot]=w; p[++cnt]=(node){tot,fi[o]};fi[o]=cnt;//debug("add o=%lld fi=%d\n",o,fi[o]);}int find(int x,int y){ll w=1ll*x*(m+1)+y,o=w%mod;for(int i=fi[o];~i;i=p[i].nxt){//debug("o=%lld i=%d\n",o,i);//ok;if(key[p[i].to]==w) return id[p[i].to];}return 0;}void init(){tot=0;memset(fi,-1,sizeof(fi));cnt=-1;}
}mp;int tot;int x[N],y[N];
bool jd[N*25];
int d24x[25]={0,-2,-2,-2,-2,-2,-1,-1,-1,-1,-1,0,0,0,0,1,1,1,1,1,2,2,2,2,2},d24y[25]={0,-2,-1,0,1,2,-2,-1,0,1,2,-2,-1,1,2,-2,-1,0,1,2,-2,-1,0,1,2};
int d8x[9]={0,-1,-1,-1,0,0,1,1,1},d8y[9]={0,-1,0,1,-1,1,-1,0,1};
int d4x[5]={0,-1,0,0,1},d4y[5]={0,0,-1,1,0};int cut;
int dfn[N*25],low[N*25],tim,bel[N*25],Id;
void tarjan(int x,int rt=0){dfn[x]=low[x]=++tim;bel[x]=Id;int son(0);for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;//if(to<=c) continue;if(!dfn[to]){tarjan(to);son++;if(low[to]>=dfn[x]){cut+=jd[x];}low[x]=min(low[x],low[to]);}else low[x]=min(low[x],dfn[to]);}if(rt&&son==1) cut-=jd[x];return;
}bool vis[N];
int nowId;
void dfs(int x,int y){int now=mp.find(x,y);vis[now]=1;for(int d=1;d<=8;d++){int nx=x+d8x[d],ny=y+d8y[d];if(nx<1||nx>n||ny<1||ny>m) continue;int to=mp.find(nx,ny);if(to>c){if(nowId==0) nowId=bel[to];else if(nowId!=bel[to]) nowId=-1;}else if(!vis[to]) dfs(nx,ny); }
}void clear(){mp.init();memset(fi,-1,sizeof(int)*(tot+1));cnt=-1;memset(jd,0,sizeof(int)*(tot+1));cut=tim=Id=0;memset(dfn,0,sizeof(int)*(tot+1));memset(low,0,sizeof(int)*(tot+1));memset(bel,0,sizeof(int)*(tot+1));memset(vis,0,sizeof(int)*(c+1));tot=0;
}void work(){n=read();m=read();tot=c=read();for(int i=1;i<=c;i++){x[i]=read();y[i]=read();mp.ins(x[i],y[i],i); }for(int i=1;i<=c;i++){for(int d=1;d<=24;d++){int nx=x[i]+d24x[d],ny=y[i]+d24y[d];if(nx<1||nx>n||ny<1||ny>m) continue; if(!mp.find(nx,ny)){mp.ins(nx,ny,++tot);int x=tot;for(int d=1;d<=4;d++){int nnx=nx+d4x[d],nny=ny+d4y[d];int to=mp.find(nnx,nny);if(to&&to>c){//printf("d=%d (%d %d) -> (%d %d)\n",d,nx,ny,nnx,nny);addline(x,to);addline(to,x);}}}int to=mp.find(nx,ny);if(to<=c) continue;if(abs(nx-x[i])<=1&&abs(ny-y[i])<=1) jd[to]=1;}}if(flag) for(int i=1;i<=n;i++){for(int j=1;j<=m;j++) printf("%d ",mp.find(i,j));puts("");}for(int i=c+1;i<=tot;i++){if(!dfn[i]){++Id;tarjan(i,1);}}if(1ll*n*m-c<2||(1ll*n*m-c==2&&(Id==1||n*m==2))){puts("-1");return;}for(int i=1;i<=c;i++){if(!vis[i]){nowId=0;dfs(x[i],y[i]);if(nowId==-1){puts("0");return;}}}if(cut||n==1||m==1) puts("1");else puts("2");return;
}signed main(){#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifmemset(fi,-1,sizeof(fi));cnt=-1;int T=read();while(T--){clear();work();}return 0;
}