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 ...
随机推荐
- 【IDEA】热部署插件Jrebel破解安装
JRebel 介绍 IDEA上原生是不支持热部署的,一般更新了 Java 文件后要手动重启 Tomcat 服务器,才能生效,浪费不少生命啊.目前对于idea热部署最好的解决方案就是安装JRebel插件 ...
- Ajax基础知识梳理
Ajax用一句话来说就是无须刷新页面即可从服务器取得数据.注意,虽然Ajax翻译过来叫异步JavaScript与XML,但是获得的数据不一定是XML数据,现在服务器端返回的都是JSON格式的文件. 完 ...
- mysql六:数据备份、pymysql模块
一 IDE工具介绍 生产环境还是推荐使用mysql命令行,但为了方便我们测试,可以使用IDE工具 掌握: #1. 测试+链接数据库 #2. 新建库 #3. 新建表,新增字段+类型+约束 #4. 设计表 ...
- Jane Austen【简·奥斯汀】
Jane Austen Jane Austen, a famous English writer, was born at Steventon, Hampshire, on December 16, ...
- HashTable, HashMap,TreeMap区别
java为数据结构中的映射定义了一个接口java.util.Map,而HashMap Hashtable和TreeMap就是它的实现类.Map是将键映射到值的对象,一个映射不能包含重复的键:每个键最多 ...
- JDK各版本新特性浅谈
JDK 5.0 自动拆装箱 枚举 可变参数 泛型 For -each 内省 静态导入 JDK 6.0 console开发控制台程序 轻量级HTTP ServerAPI 支持脚本语言 使用Compile ...
- POJ1741 Tree (点分治)
Tree Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 25772 Accepted: 8566 Description ...
- ios开发学习笔记001-C语言基础知识
先来学习一下C语言基础知识,总结如下: 在xcode下编写代码. 1.编写代码 2.编译:cc –c 文件名.c 编译成功会生成一个 .o的目标文件 3.链接:把目标文件.o和系统自带的库合并在一起, ...
- Python Unicode与中文处理
转自:http://blog.csdn.net/dao123mao/article/details/5396497 python中的unicode是让人很困惑.比较难以理解的问题,本文力求彻底解决这些 ...
- 微信小程序-----校园头条详细开发之注册登录
1.注册登录功能的实现 1.1结构 1.2 代码实现 1.2.1 为了通信的安全着想,在此我是通过小程序端获得code,然后传递给后端,在后端向微信后台发送api请求,解密,从而得到用户的唯一标示o ...