$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 ;
}

LOJ#2084. 「NOI2016」网格的更多相关文章

  1. 【LOJ】#2084. 「NOI2016」网格

    题解 之前用的mapTLE了,今天用了个hash把题卡了过去,AC数++ 我们只要保留一个点为中心周围5 * 5个格子就可以 如果一个点周围5*5个格子有两个不连通,那么显然输出0 如果一个出现了一个 ...

  2. 「NOI2016」网格 解题报告

    「NOI2016」网格 容易注意到,答案最多为2,也就是说答案为-\(1,0,1,2\)四种,考虑逐个判断. 无解的情况比较简单 如果\(nm\le c+1\),显然无解 如果\(nm=c+2\),判 ...

  3. LOJ#2086. 「NOI2016」区间

    $n \leq 500000$个区间,从中挑出一些,使得至少有一个点被$m$个选中区间包含,且选中区间长度的极差最小. 区间题死脑筋晚期:把区间按左端点排序,然后右端点用个优先队列来弹,然后需要维护下 ...

  4. *LOJ#2085. 「NOI2016」循环之美

    $n \leq 1e9,m \leq 1e9,k \leq 2000$,求$k$进制下$\frac{x}{y}$有多少种不同的纯循环数取值,$1 \leq x \leq n,1 \leq y \leq ...

  5. LOJ#2083. 「NOI2016」优秀的拆分

    $n \leq 30000$的字符串,问其所有子串的所有AABB形式的拆分有多少种.$t \leq 10$组询问. $n^3$过80,$n^2$过95,鬼去写正解.. $n^2$:先枚举一次算每个位置 ...

  6. Loj #2719. 「NOI2018」冒泡排序

    Loj #2719. 「NOI2018」冒泡排序 题目描述 最近,小 S 对冒泡排序产生了浓厚的兴趣.为了问题简单,小 S 只研究对 *\(1\) 到 \(n\) 的排列*的冒泡排序. 下面是对冒泡排 ...

  7. Loj #2192. 「SHOI2014」概率充电器

    Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...

  8. Loj #3096. 「SNOI2019」数论

    Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...

  9. Loj #3093. 「BJOI2019」光线

    Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...

随机推荐

  1. Oracle - 存储过程、函数、包的使用练习-雇员

    --存储过程范例:得到雇员表 emp 的记录数 begin --说明:若过程中要向外抛异常,请使用 exception when others then raise; 这个抛出的异常在程序里是可以捕获 ...

  2. django+xadmin在线教育平台(二)

    老话总是没错的,工欲善其事,必先利其器 教你安装pycharm,mysql,navicat,python相关环境. windows下搭建开发环境 2-1 pycharm,mysql,Navicat安装 ...

  3. Redis之String类型操作

    接口IRedisDaoStr: package com.net.test.redis.base.dao; import java.util.List; import java.util.Map; /* ...

  4. python正则表达式入门篇

    文章来源于:https://www.cnblogs.com/chuxiuhong/p/5885073.html Python 正则表达式入门(初级篇) 本文主要为没有使用正则表达式经验的新手入门所写. ...

  5. Find a path HDU - 5492 (dp)

    Find a path Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  6. 动态规划:POJ2576-Tug of War(二维费用的背包问题)

    Tug of War Time Limit: 3000MS Memory Limit: 65536K Description A tug of war is to be arranged at the ...

  7. poj 2533Longest Ordered Subsequence

    Longest Ordered Subsequence Description A numeric sequence of ai is ordered if a1 < a2 < - < ...

  8. HDU 3966 Aragorn's Story 树链拋分

    一.写在前面 终于开始开坑link-cut-tree这个了,对于网上找到的大佬的前进路线,进行了一番研发,发现实际上可以实现对于树链拋分的制作.经历了若干长时间之后终于打了出来(为什么每次学什么东西都 ...

  9. UVA 10859 Placing Lamppost 树形DP+二目标最优解的求解方案

    题意:给定一个无向,无环,无多重边,要求找出最少的若干点,使得,每条边之中至少有一个点上有街灯.在满足上述条件的时候将还需要满足让两个点被选择的边的数量尽量多. 题解: 对于如何求解最小的节点数目这点 ...

  10. git pull免密码拉取

    ssh到服务器上,原来基于public/private key pair的方法不好使了. 1.1 创建文件存储GIT用户名和密码 在%HOME%目录中,一般为C:\users\Administrato ...