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 ...
随机推荐
- js数组删除(splice和delete)
最近一直在写js的数组,然后就发现了很奇怪的问题,后来才发现了规律. 删除数据的一行,一般有两种方法,一个是splice,一个是delete: splice:删除了数组后,数组的长度会自动变化.用法: ...
- ZendFramework-2.4 源代码 - 关于MVC - Model层类图
- thinkphp 3.2.3 程序执行时序图
- javaWeb开发中常见的问题
1.修改表单提交的时候不好使可能是因为没写对应隐藏域的ID 2.el表达式在js代码中要加“”,例如 "${}" 3.JavaScript中的函数也有重载的特性.如果两个input ...
- [译]The Python Tutorial#3. An Informal Introduction to Python
3. An Informal Introduction to Python 在以下示例中,输入和输出以提示符(>>>和...)的出现和消失来标注:如果想要重现示例,提示符出现时,必须 ...
- 初学python来进行odoo12版本开发
这是我的第一篇博客.请多多指教! 首先要下载odoo-12的源代码 官方下载路径: https://github.com/odoo/odoo/archive/12.0.zip 随便新 ...
- static关键字 详解
原文地址:http://blog.csdn.net/keyeagle/article/details/6708077 google了近三页的关于C语言中static的内容,发现可用的信息很少,要么长篇 ...
- vue --子父组件传值
1.父组件可以使用 props 把数据传给子组件. 2.子组件可以使用 $emit 触发父组件的自定义事件. vm.$emit( event, arg ) //触发当前实例上的事件 vm.$on( e ...
- laravel5.2总结--数据迁移
迁移就像是数据库中的版本控制,它让团队能够轻松的修改跟共享应用程序的数据库结构. 1 创建一个迁移 1.1 使用artisan命令make:migration来创建一个新的迁移: ph ...
- C#实现eval 进行四则运算(有码)
在JavaScript中实现四则运算很简单,只需要调用eval函数就行了,但是不知道什么原因万能的.NET却没有封装这个函数~ 在这里为大家封装了一个C#版本的eval函数,具体的设计参考了<大 ...