$n,m leq 1e9$,$n*m$的网格中有$c leq 1e5$个是黑的,其他是白的。问:使至少两个白的不连通,最少需要再把几个白的涂黑。
可以发现答案是-1,0,1,2啦。-1要么没白的,要么一个白的,要么两个相邻白的。如果是两个不相邻白的答案就是0,这些可以特判掉。
其他的情况,可以建个图判连通、判割点。但网格太大了,可以发现连通的话只要关心所有黑点的周围八个白点之间的连通性即可,于是就记下这些点,离散化完分别按$x$和$y$排序来连边。但这样仍不能判割点,比如
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 1
0 0 0 0 0 0 0
0 0 0 0 0 0 0
0 0 0 0 0 0 0
这样,只把
0 0
0 1
0 0
拿出来建图,会出现3个割点,但不是我们想要的。为避免这种情况,需要把离散化后的周围区域再围一圈。变成这样:
0 0 0
0 0 0
0 0 1
0 0 0
0 0 0
注意到有些边界上的点不能“围”,比如上面例子,右边不能再围一圈。至于怎么围,其实离散化之前,把1,n加入$x$离散化数组中,1,m加入$y$离散化数组中,就可以直接围了,用hash保证不要重复加点即可。
然而,n=1和m=1需要特殊判断。。我就问出题人,出这种大分类大模拟大特判题是何居心。。
1 //#include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 //#include<math.h> 5 //#include<set> 6 //#include<queue> 7 //#include<bitset> 8 //#include<vector> 9 #include<algorithm> 10 #include<stdlib.h> 11 using namespace std; 12 13 #define LL long long 14 int qread() 15 { 16 char c; int s=0,f=1; while ((c=getchar())<'0' || c>'9') (c=='-') && (f=-1); 17 do s=s*10+c-'0'; while ((c=getchar())>='0' && c<='9'); return s*f; 18 } 19 20 //Pay attention to '-' , LL and double of qread!!!! 21 22 int T,n,m,c; 23 #define maxn 2400011 24 #define maxm 10000011 25 26 int Abs(int x) {return x>0?x:-x;} 27 28 struct Poi 29 { 30 int x,y,id; 31 bool operator == (const Poi &b) const {return x==b.x && y==b.y;} 32 }cc[maxn]; 33 bool cmpx(const Poi &a,const Poi &b) {return a.x<b.x || (a.x==b.x && a.y<b.y);} 34 bool cmpy(const Poi &a,const Poi &b) {return a.y<b.y || (a.y==b.y && a.x<b.x);} 35 36 int px[maxn],py[maxn],lx,ly; 37 38 #define maxh 1000007 39 struct Hash 40 { 41 struct Edge{int to,x,y,next;}edge[maxn]; int first[maxh],le; 42 void clear() {memset(first,0,sizeof(first)); le=2;} 43 int geth(int x,int y) {return (x*1000000000ll+y)%maxh;} 44 void in(int x,int y,int id) 45 {int h=geth(x,y); Edge &e=edge[le]; e.to=id; e.x=x; e.y=y; e.next=first[h]; first[h]=le++;} 46 void insert(int x,int y,int id) {if (!~find(x,y)) in(x,y,id);} 47 int find(int x,int y) 48 { 49 int h=geth(x,y); 50 for (int i=first[h];i;i=edge[i].next) if (edge[i].x==x && edge[i].y==y) return edge[i].to; 51 return -1; 52 } 53 }h,hh; 54 55 const int dx[]={-1,0,1,-1,1,-1,0,1}, 56 dy[]={-1,-1,-1,0,0,1,1,1}, 57 ddx[]={-1,1,0,0},ddy[]={0,0,-1,1}; 58 59 int TOT,ANS,dfn[maxn],Time,low[maxn],top; Poi sta[maxn]; 60 struct Edge{int to,next;}edge[maxm]; int first[maxn],le=2; 61 void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;} 62 void insert(int x,int y) {in(x,y); in(y,x);} 63 64 void tarjan(int id,int fa) 65 { 66 TOT++; 67 int son=0; 68 dfn[id]=low[id]=++Time; 69 for (int i=first[id];i;i=edge[i].next) 70 { 71 Edge &e=edge[i]; int u=e.to; 72 if (!dfn[u]) 73 { 74 sta[++top]=(Poi){id,u,0}; 75 son++; 76 tarjan(u,id); 77 low[id]=min(low[id],low[u]); 78 if (low[u]>=dfn[id]) 79 { 80 // cout<<id<<' '<<u<<endl; 81 if (fa) ANS=1; 82 while (sta[top].x!=id || sta[top].y!=u) top--; 83 top--; 84 } 85 } 86 else if (u!=fa && dfn[u]<dfn[id]) 87 { 88 sta[++top]=(Poi){id,u,0}; 89 low[id]=min(low[id],dfn[u]); 90 } 91 } 92 if (fa==0 && son>1) ANS=1; 93 } 94 95 int main() 96 { 97 T=qread(); 98 while (T--) 99 { 100 n=qread(); m=qread(); c=qread(); 101 for (int i=1;i<=c;i++) {cc[i].x=qread(); cc[i].y=qread();} 102 if (1ll*n*m-c<2) puts("-1"); 103 else if (1ll*n*m-c==2) 104 { 105 if (c==0) {puts("-1"); continue;} 106 sort(cc+1,cc+1+c,cmpx); 107 int x1=0,x2=0,y1,y2; 108 for (int x=1,y=1,i=1;i<=c;i++,x+=(y==m),y=y==m?1:y+1) 109 { 110 if (cc[i].x!=x || cc[i].y!=y) 111 { 112 if (!x1) x1=x,y1=y; 113 else x2=x,y2=y; 114 i--; 115 } 116 } 117 if (x1==0) {x1=n; y1=m-1; x2=n; y2=m;} 118 else if (x2==0) {x2=n; y2=m;} 119 if (Abs(x1-x2)+Abs(y1-y2)==1) puts("-1"); 120 else puts("0"); 121 } 122 else 123 { 124 if (c==0) 125 { 126 if (n==1 || m==1) puts("1"); 127 else puts("2"); 128 continue; 129 } 130 131 int tc=c; 132 for (int i=1;i<=c;i++) cc[i].id=0; 133 lx=ly=0; 134 hh.clear(); 135 for (int i=1;i<=c;i++) hh.insert(cc[i].x,cc[i].y,i); 136 for (int i=1,tmp=c;i<=tmp;i++) 137 { 138 px[++lx]=cc[i].x; py[++ly]=cc[i].y; 139 for (int j=0;j<8;j++) 140 { 141 int xx=dx[j]+cc[i].x,yy=dy[j]+cc[i].y; 142 if (xx<=0 || xx>n || yy<=0 || yy>m || ~hh.find(xx,yy)) continue; 143 c++; cc[c].x=xx; cc[c].y=yy; cc[c].id=cc[c-1].id+1; hh.insert(xx,yy,0); 144 px[++lx]=xx; py[++ly]=yy; 145 } 146 } 147 148 px[++lx]=1; px[++lx]=n; sort(px+1,px+1+lx); lx=unique(px+1,px+1+lx)-px-1; 149 py[++ly]=1; py[++ly]=m; sort(py+1,py+1+ly); ly=unique(py+1,py+1+ly)-py-1; 150 for (int i=1;i<=c;i++) cc[i].x=lower_bound(px+1,px+1+lx,cc[i].x)-px, 151 cc[i].y=lower_bound(py+1,py+1+ly,cc[i].y)-py; 152 153 hh.clear(); for (int i=1;i<=c;i++) hh.insert(cc[i].x,cc[i].y,cc[i].id); 154 for (int i=1;i<=ly;i++) if (!~hh.find(1,i)) 155 {cc[c+1]=(Poi){1,i,cc[c].id+1}; c++; hh.insert(cc[c].x,cc[c].y,cc[c].id);} 156 for (int i=1;i<=ly;i++) if (!~hh.find(lx,i)) 157 {cc[c+1]=(Poi){lx,i,cc[c].id+1}; c++; hh.insert(cc[c].x,cc[c].y,cc[c].id);} 158 for (int i=1;i<=lx;i++) if (!~hh.find(i,1)) 159 {cc[c+1]=(Poi){i,1,cc[c].id+1}; c++; hh.insert(cc[c].x,cc[c].y,cc[c].id);} 160 for (int i=1;i<=lx;i++) if (!~hh.find(i,ly)) 161 {cc[c+1]=(Poi){i,ly,cc[c].id+1}; c++; hh.insert(cc[c].x,cc[c].y,cc[c].id);} 162 163 memset(first,0,sizeof(first)); le=2; 164 sort(cc+1,cc+1+c,cmpx); 165 for (int i=1;i<c;i++) if (cc[i].id && cc[i+1].id && cc[i].x==cc[i+1].x) insert(cc[i].id,cc[i+1].id); 166 sort(cc+1,cc+1+c,cmpy); 167 for (int i=1;i<c;i++) if (cc[i].id && cc[i+1].id && cc[i].y==cc[i+1].y) insert(cc[i].id,cc[i+1].id); 168 169 TOT=ANS=Time=top=0; 170 memset(dfn,0,sizeof(dfn)); 171 tarjan(1,0); 172 if (TOT<c-tc) puts("0"); 173 else if ((n==1 || m==1) && (n*m>TOT)) puts("1"); 174 else if (ANS) puts("1"); else puts("2"); 175 } 176 } 177 178 return 0; 179 }