LOJ#2084. 「NOI2016」网格
$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」网格的更多相关文章
- 【LOJ】#2084. 「NOI2016」网格
题解 之前用的mapTLE了,今天用了个hash把题卡了过去,AC数++ 我们只要保留一个点为中心周围5 * 5个格子就可以 如果一个点周围5*5个格子有两个不连通,那么显然输出0 如果一个出现了一个 ...
- 「NOI2016」网格 解题报告
「NOI2016」网格 容易注意到,答案最多为2,也就是说答案为-\(1,0,1,2\)四种,考虑逐个判断. 无解的情况比较简单 如果\(nm\le c+1\),显然无解 如果\(nm=c+2\),判 ...
- LOJ#2086. 「NOI2016」区间
$n \leq 500000$个区间,从中挑出一些,使得至少有一个点被$m$个选中区间包含,且选中区间长度的极差最小. 区间题死脑筋晚期:把区间按左端点排序,然后右端点用个优先队列来弹,然后需要维护下 ...
- *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 ...
- LOJ#2083. 「NOI2016」优秀的拆分
$n \leq 30000$的字符串,问其所有子串的所有AABB形式的拆分有多少种.$t \leq 10$组询问. $n^3$过80,$n^2$过95,鬼去写正解.. $n^2$:先枚举一次算每个位置 ...
- Loj #2719. 「NOI2018」冒泡排序
Loj #2719. 「NOI2018」冒泡排序 题目描述 最近,小 S 对冒泡排序产生了浓厚的兴趣.为了问题简单,小 S 只研究对 *\(1\) 到 \(n\) 的排列*的冒泡排序. 下面是对冒泡排 ...
- Loj #2192. 「SHOI2014」概率充电器
Loj #2192. 「SHOI2014」概率充电器 题目描述 著名的电子产品品牌 SHOI 刚刚发布了引领世界潮流的下一代电子产品--概率充电器: 「采用全新纳米级加工技术,实现元件与导线能否通电完 ...
- Loj #3096. 「SNOI2019」数论
Loj #3096. 「SNOI2019」数论 题目描述 给出正整数 \(P, Q, T\),大小为 \(n\) 的整数集 \(A\) 和大小为 \(m\) 的整数集 \(B\),请你求出: \[ \ ...
- Loj #3093. 「BJOI2019」光线
Loj #3093. 「BJOI2019」光线 题目描述 当一束光打到一层玻璃上时,有一定比例的光会穿过这层玻璃,一定比例的光会被反射回去,剩下的光被玻璃吸收. 设对于任意 \(x\),有 \(x\t ...
随机推荐
- CentOS 7+ 环境下安装MySQL
在CentOS中默认安装有MariaDB,但是我们需要的是MySQL,安装MySQL可以覆盖MariaDB MariaDB数据库管理系统是MySQL的一个分支,主要由开源社区在维护,采用GPL授权许可 ...
- jsp引用servlet生成的验证码代码演示
此演示代码主要包括以下三部分:1.checkCode.java:用于生成验证码2.checkCodeServler3.check.jsp 验证 下面是checkCode.java的内容: 复制代码代码 ...
- Android_组件_Activity基础
一.概述 Activity是应用组件,提供了用户交互的窗口.一个应用由多个彼此联系的Activity组成.它大多数情况是全屏窗口显示,也可以作为悬浮窗口 或者 多窗口模式. 二.生命周期 下图是来自A ...
- batch-normalization为什么效果好
batch-normalization为什么效果好 深度学习中 Batch Normalization为什么效果好? - 龙鹏-言有三的回答 - 知乎 https://www.zhihu.com/qu ...
- 基于neo4j图数据库,实现人口关系大图的基本思路及实现方案。
近期由于工作需要,需要做一个人口关系大图的存储及检索方案,我们主要的数据对象有:人口(年龄,身份证号码,性别..) :学校信息(学校地址,学校名称,学校级别,学校下边的年级班级..):就职信息(公司名 ...
- 51nod_1154 回文串的划分
说实话..最开始看这题感觉一定好难...好高大上...我的马拉车还不熟....这种..但是本着做不出来也要至少看看的心态,吧个题看完了..然后简单的想了想,好像是个挺直观的动态规划,因为看到数据几乎就 ...
- Sql日期时间格式转换(转 子夜.)
sql server2000中使用convert来取得datetime数据类型样式(全) 日期数据格式的处理,两个示例: CONVERT(varchar(16), 时间一, 20) 结果:2007-0 ...
- Redis实现之复制(二)
PSYNC命令的实现 在Redis实现之复制(一)这一章中,我们介绍了PSYNC命令和它的工作机制,但一直没有说明PSYNC命令的参数以及返回值.现在,我们了解了运行ID.复制偏移量.复制积压缓冲区以 ...
- Java消息中间件--初级篇
一. 为什么使用消息中间件? 假设用户登录系统 传统方式 用户登录 调用短息服务 积分服务 日志服务等各种服务 如果短息服务出现问题就无法发送短信而且用户登录成功必须所有调用全部完成返回 ...
- 【01】《html5权威指南》(扫描版)(全)
[01]<html5权威指南>(扫描版)(全) []魔芋:无高清电子书. 只看第五部分,高级功能. 作者:(美)弗里曼 著,谢延晟,牛化成,刘美英 译 [美]adam freeman ...