$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需要特殊判断。。我就问出题人,出这种大分类大模拟大特判题是何居心。。

 //#include<iostream>
#include<cstring>
#include<cstdio>
//#include<math.h>
//#include<set>
//#include<queue>
//#include<bitset>
//#include<vector>
#include<algorithm>
#include<stdlib.h>
using namespace std; #define LL long long
int qread()
{
char c; int s=,f=; while ((c=getchar())<'' || c>'') (c=='-') && (f=-);
do s=s*+c-''; while ((c=getchar())>='' && c<=''); return s*f;
} //Pay attention to '-' , LL and double of qread!!!! int T,n,m,c;
#define maxn 2400011
#define maxm 10000011 int Abs(int x) {return x>?x:-x;} struct Poi
{
int x,y,id;
bool operator == (const Poi &b) const {return x==b.x && y==b.y;}
}cc[maxn];
bool cmpx(const Poi &a,const Poi &b) {return a.x<b.x || (a.x==b.x && a.y<b.y);}
bool cmpy(const Poi &a,const Poi &b) {return a.y<b.y || (a.y==b.y && a.x<b.x);} int px[maxn],py[maxn],lx,ly; #define maxh 1000007
struct Hash
{
struct Edge{int to,x,y,next;}edge[maxn]; int first[maxh],le;
void clear() {memset(first,,sizeof(first)); le=;}
int geth(int x,int y) {return (x*1000000000ll+y)%maxh;}
void in(int x,int y,int id)
{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++;}
void insert(int x,int y,int id) {if (!~find(x,y)) in(x,y,id);}
int find(int x,int y)
{
int h=geth(x,y);
for (int i=first[h];i;i=edge[i].next) if (edge[i].x==x && edge[i].y==y) return edge[i].to;
return -;
}
}h,hh; const int dx[]={-,,,-,,-,,},
dy[]={-,-,-,,,,,},
ddx[]={-,,,},ddy[]={,,-,}; int TOT,ANS,dfn[maxn],Time,low[maxn],top; Poi sta[maxn];
struct Edge{int to,next;}edge[maxm]; int first[maxn],le=;
void in(int x,int y) {Edge &e=edge[le]; e.to=y; e.next=first[x]; first[x]=le++;}
void insert(int x,int y) {in(x,y); in(y,x);} void tarjan(int id,int fa)
{
TOT++;
int son=;
dfn[id]=low[id]=++Time;
for (int i=first[id];i;i=edge[i].next)
{
Edge &e=edge[i]; int u=e.to;
if (!dfn[u])
{
sta[++top]=(Poi){id,u,};
son++;
tarjan(u,id);
low[id]=min(low[id],low[u]);
if (low[u]>=dfn[id])
{
// cout<<id<<' '<<u<<endl;
if (fa) ANS=;
while (sta[top].x!=id || sta[top].y!=u) top--;
top--;
}
}
else if (u!=fa && dfn[u]<dfn[id])
{
sta[++top]=(Poi){id,u,};
low[id]=min(low[id],dfn[u]);
}
}
if (fa== && son>) ANS=;
} int main()
{
T=qread();
while (T--)
{
n=qread(); m=qread(); c=qread();
for (int i=;i<=c;i++) {cc[i].x=qread(); cc[i].y=qread();}
if (1ll*n*m-c<) puts("-1");
else if (1ll*n*m-c==)
{
if (c==) {puts("-1"); continue;}
sort(cc+,cc++c,cmpx);
int x1=,x2=,y1,y2;
for (int x=,y=,i=;i<=c;i++,x+=(y==m),y=y==m?:y+)
{
if (cc[i].x!=x || cc[i].y!=y)
{
if (!x1) x1=x,y1=y;
else x2=x,y2=y;
i--;
}
}
if (x1==) {x1=n; y1=m-; x2=n; y2=m;}
else if (x2==) {x2=n; y2=m;}
if (Abs(x1-x2)+Abs(y1-y2)==) puts("-1");
else puts("");
}
else
{
if (c==)
{
if (n== || m==) puts("");
else puts("");
continue;
} int tc=c;
for (int i=;i<=c;i++) cc[i].id=;
lx=ly=;
hh.clear();
for (int i=;i<=c;i++) hh.insert(cc[i].x,cc[i].y,i);
for (int i=,tmp=c;i<=tmp;i++)
{
px[++lx]=cc[i].x; py[++ly]=cc[i].y;
for (int j=;j<;j++)
{
int xx=dx[j]+cc[i].x,yy=dy[j]+cc[i].y;
if (xx<= || xx>n || yy<= || yy>m || ~hh.find(xx,yy)) continue;
c++; cc[c].x=xx; cc[c].y=yy; cc[c].id=cc[c-].id+; hh.insert(xx,yy,);
px[++lx]=xx; py[++ly]=yy;
}
} px[++lx]=; px[++lx]=n; sort(px+,px++lx); lx=unique(px+,px++lx)-px-;
py[++ly]=; py[++ly]=m; sort(py+,py++ly); ly=unique(py+,py++ly)-py-;
for (int i=;i<=c;i++) cc[i].x=lower_bound(px+,px++lx,cc[i].x)-px,
cc[i].y=lower_bound(py+,py++ly,cc[i].y)-py; hh.clear(); for (int i=;i<=c;i++) hh.insert(cc[i].x,cc[i].y,cc[i].id);
for (int i=;i<=ly;i++) if (!~hh.find(,i))
{cc[c+]=(Poi){,i,cc[c].id+}; c++; hh.insert(cc[c].x,cc[c].y,cc[c].id);}
for (int i=;i<=ly;i++) if (!~hh.find(lx,i))
{cc[c+]=(Poi){lx,i,cc[c].id+}; c++; hh.insert(cc[c].x,cc[c].y,cc[c].id);}
for (int i=;i<=lx;i++) if (!~hh.find(i,))
{cc[c+]=(Poi){i,,cc[c].id+}; c++; hh.insert(cc[c].x,cc[c].y,cc[c].id);}
for (int i=;i<=lx;i++) if (!~hh.find(i,ly))
{cc[c+]=(Poi){i,ly,cc[c].id+}; c++; hh.insert(cc[c].x,cc[c].y,cc[c].id);} memset(first,,sizeof(first)); le=;
sort(cc+,cc++c,cmpx);
for (int i=;i<c;i++) if (cc[i].id && cc[i+].id && cc[i].x==cc[i+].x) insert(cc[i].id,cc[i+].id);
sort(cc+,cc++c,cmpy);
for (int i=;i<c;i++) if (cc[i].id && cc[i+].id && cc[i].y==cc[i+].y) insert(cc[i].id,cc[i+].id); TOT=ANS=Time=top=;
memset(dfn,,sizeof(dfn));
tarjan(,);
if (TOT<c-tc) puts("");
else if ((n== || m==) && (n*m>TOT)) puts("");
else if (ANS) puts(""); else puts("");
}
} return ;
}

最新文章

  1. mysql中字符集的比较
  2. ES6中的var let const应如何选择
  3. Java-编写一个jdbc操作类
  4. Android 自定义View修炼-Android 实现自定义的卫星式菜单(弧形菜单)View
  5. jQuery_基础
  6. 阅读UML类图和时序图
  7. C# 创建Word项目标号列表、多级编号列表
  8. Python之路,进程、线程、协程篇
  9. spring Ioc 实践
  10. 微服务(Microservice)那点事
  11. Visual Studio 后期生成事件命令行
  12. 【python笔记】python中的list、tuple、set、dict用法简析
  13. java project 项目在 linux 下面部署方法
  14. 《Go语言实战》笔记之第三章 ----包
  15. 第1章:初始C#及其开发环境
  16. JS将秒转换为 天
  17. CNN延拓至 复数域
  18. Excel应用----制作二级下拉菜单【转】
  19. 转 DOS 8.3 文件名命名规则
  20. KVM硬件辅助虚拟化之 EPT in Nested Virtualization

热门文章

  1. XPATH如何选择,t选取,包含某一属性的节点, 不包含某一个属性的节点?
  2. 4.在Cisco Packet Tracerl里路由器密码重置
  3. Linux下面自动清理超过指定大小的文件
  4. Python_列表、字典、字符串、集合操作
  5. CentOS Linux release 7.6.1810全新安装 Zimbra 8.8.12邮箱
  6. .net core IdentityServer4 使用query参数
  7. 初学js之qq聊天实例
  8. 三次样条插值matlab实现
  9. 库函数的使用:sscanf的使用方法
  10. Kubespray部署Kubernetes 1.13.0(使用本地镜像仓库)