BZOJ4651 NOI2016网格(割点)
首先显然可以通过孤立角落里的跳蚤使其不连通,所以只要有解答案就不会大于2。同样显然的一点是当且仅当跳蚤数量<=2且连通时无解。做法其实也很显然了:特判无解,若跳蚤不连通输出0,否则看图中是否无割点(即点双连通),若无答案为2,否则为1。
现在的问题是这个图实在是太大了。正常的离散化可能仍然需要留下c2个点。这个时候发现部分分很足于是我们就可以弃疗了。
比较直观的一点是附近没有蛐蛐的跳蚤不太可能被割开。显然只有周围八连通有蛐蛐的位置才可能成为割点。那么要判断其是否是割点还需要再取周围一圈。所以取出每个蛐蛐的周围两圈跳蚤放在一张图里,之间四连通的连边。此时若有某个蛐蛐周围两圈的跳蚤处于不同连通块,则说明跳蚤本身就不连通;否则tarjan求一发割点就可以了。注意这里割点必须与蛐蛐八连通(或在边界)才是原图的割点,正确性是显然的,但好像没想明白不这么干会有什么问题。
map被卡常习惯了。bzoj过了,luoguT两个点。
upd:莫名其妙的把一个完全能用数组的东西用map存了。然后对于点的初始化在新建点的时候进行,不要直接memset。就能过掉了。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
#define ll long long
#define N 100010
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int T,n,m,c,dfn[N<<],low[N<<],cnt,tot,t,p[N<<],id[][],fa[N<<];
bool tag[N<<];
struct data
{
int x,y;
bool operator <(const data&a) const
{
return x<a.x||x==a.x&&y<a.y;
}
}a[N];
map<data,int> f;
int wx[]={,,,-},wy[]={,,-,};
struct data2{int to,nxt;
}edge[N<<];
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
bool tarjan(int k,int from)
{
dfn[k]=low[k]=++tot;int son=;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from)
{
if (dfn[edge[i].to]) low[k]=min(low[k],dfn[edge[i].to]);
else
{
if (tarjan(edge[i].to,k)) return ;
son++;low[k]=min(low[k],low[edge[i].to]);
if (from!=-&&low[edge[i].to]>=dfn[k]||son>&&from==-) if (tag[k]) return ;
}
}
return ;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj4651.in","r",stdin);
freopen("bzoj4651.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
T=read();
while (T--)
{
n=read(),m=read(),c=read();f.clear();
for (int i=;i<=c;i++) a[i].x=read(),a[i].y=read(),f[a[i]]=-;
if (1ll*n*m-c<=) {cout<<-<<endl;continue;}
if (1ll*n*m-c==)
{
int vx[],vy[],t=-;
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
if (f.find((data){i,j})==f.end()) t++,vx[t]=i,vy[t]=j;
if (vx[]==vx[]&&abs(vy[]-vy[])==||vy[]==vy[]&&abs(vx[]-vx[])==) cout<<-<<endl;
else cout<<<<endl;
continue;
}
cnt=;t=;
for (int i=;i<=c;i++)
{
for (int x=-;x<=;x++)
for (int y=-;y<=;y++)
if (a[i].x+x>=&&a[i].x+x<=n&&a[i].y+y>=&&a[i].y+y<=m)
{
if (f.find((data){a[i].x+x,a[i].y+y})==f.end())
f[(data){a[i].x+x,a[i].y+y}]=++cnt,id[x+][y+]=cnt,fa[cnt]=cnt,tag[cnt]=p[cnt]=dfn[cnt]=;
else id[x+][y+]=f[(data){a[i].x+x,a[i].y+y}];
if (a[i].x+x==||a[i].x+x==n||a[i].y+y==||a[i].y+y==m||abs(x)<=&&abs(y)<=) tag[id[x+][y+]]=;
}
else f[(data){a[i].x+x,a[i].y+y}]=-,id[x+][y+]=-;
for (int x=;x<=;x++)
for (int y=;y<=;y++)
for (int k=;k<;k++)
if (x+wx[k]>=&&x+wx[k]<=&&y+wy[k]>=&&y+wy[k]<=&&~id[x][y]&&~id[x+wx[k]][y+wy[k]])
addedge(id[x][y],id[x+wx[k]][y+wy[k]]),fa[find(id[x+wx[k]][y+wy[k]])]=find(id[x][y]);
}
bool flag=;
for (int i=;i<=c;i++)
{
int t=-;
for (int x=-;x<=;x++)
for (int y=-;y<=;y++)
{
int p=f[(data){a[i].x+x,a[i].y+y}];
if (~p) if (t==-) t=find(p);else if (t!=find(p)) {flag=;break;}
}
if (!flag) break;
}
if (!flag) {cout<<<<endl;continue;}
if (n==||m==) {cout<<<<endl;continue;}
tot=;
for (int i=;i<=cnt;i++)
if (!dfn[i]&&tarjan(i,-)) {cout<<<<endl;flag=;break;}
if (flag) cout<<<<endl;
}
return ;
}
BZOJ4651 NOI2016网格(割点)的更多相关文章
- [UOJ#220][BZOJ4651][Noi2016]网格
[UOJ#220][BZOJ4651][Noi2016]网格 试题描述 跳蚤国王和蛐蛐国王在玩一个游戏. 他们在一个 n 行 m 列的网格上排兵布阵.其中的 c 个格子中 (0≤c≤nm),每个格子有 ...
- [BZOJ4651][NOI2016]网格(Tarjan)
下面直接给出结论,相关证明见官方题解. 1.若跳蚤数不超过1或仅有两只跳蚤且相邻,则答案为-1. 2.若跳蚤形成的连通块个数大于1,则答案为0. 3.若跳蚤之间建图存在割点,则答案为1. 4.否则为2 ...
- BZOJ4651 & 洛谷1173 & UOJ220:[NOI2016]网格——题解(附debug数据)
https://www.lydsy.com/JudgeOnline/problem.php?id=4651 https://www.luogu.org/problemnew/show/P1173#su ...
- BZOJ4651/UOJ220 [Noi2016]网格
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 并不对劲的bzoj4651:loj2084:uoj220:p1173:[NOI2016]网格
题目大意 有一个\(n*m\)(\(n,m\leq10^9\))的网格,每个格子是空地或障碍(\(障碍数\leq10^5\)) 定义两块空地连通,当且仅当它们是"相邻的两块空地"或 ...
- [Noi2016]网格
来自FallDream的博客,未经允许,请勿转载,谢谢. 跳蚤国王和蛐蛐国王在玩一个游戏. 他们在一个 n 行 m 列的网格上排兵布阵.其中的 c 个格子中 (0≤c≤nm),每个格子有一只蛐蛐, ...
- 洛谷P1173 [NOI2016]网格
这个码量绝对是业界大毒瘤...... 300行,6.5k,烦的要死...... 题意:给你一个网格图,里面有0或1.你需要把一些0换成1使得存在某两个0不四联通.输出最小的换的数量.无解-1. n,m ...
- UOJ220 [NOI2016] 网格 【割顶】【并查集】
题目分析: 答案显然只有{-1,0,1,2}四种. 对于答案等于-1的情况,只有两种情况,一种是只剩一只跳蚤,另一种是只剩两只跳蚤且他们四连通,这个很好判. 对于答案等于0的情况,那说明联通块大于1, ...
- NOI2016
luoguP1712 [NOI2016]区间 这是一道送分题. 对于我这种每天抄题解不动脑子思维僵化得厉害的智障选手就是送命题. 一直在想端点排序各种Treap搞... 正解: 已知一些区间,如何判断 ...
随机推荐
- nignx 配置服务集群
前言:这里只是简单介绍Nginx简单APP Server集群的搭建和设置发向代理. 后续有时间我会陆续加上Nginx的基础知识.三种负载均衡的策略设置.实现算法的介绍.(最后如果有测试环境,再模拟Ng ...
- Angular2入门学习
最近项目使用angular2,1和2版本变化大变样.下面总结一些学习网址及安装步骤. 中文官网(必看): https://angular.cn 懒人学习: http://www.imooc.com/l ...
- 《高性能MySQL》笔记——MySQL建表数据类型的选择
前段时间看了<高性能MySQL>中的选择优化的数据类型,这里主要是做一下笔记. 首先数据选择有几个简单原则: 更小的通常更好.一般情况下,应该尽量使用可以正确存储数据的最小数据类型.例如只 ...
- PHP创建MySQL并引入后执行sql语句
一:创建sql.php文件 <?php function sqlMethod($sql){ $servername = "localhost"; $username = &q ...
- Python系列5之模块
模块 1. 模块的分类 模块,又称构件,是能够单独命名并独立地完成一定功能的程序语句的集合(即程序代码和数据结构的集合体). (1)自定义模块 自己定义的一些可以独立完成某个功能的一段程序语句,可以是 ...
- Leecode刷题之旅-C语言/python-88合并两个有序数组
/* * @lc app=leetcode.cn id=88 lang=c * * [88] 合并两个有序数组 * * https://leetcode-cn.com/problems/merge-s ...
- Linux编程之Epoll高并发
网络上所有资料都说epoll是高并发.单线程.IO重叠服用的首选架构,比select和poll性能都要好,特别是在有大量不活跃连接的情况下.具体原理就不阐述了,下面说说使用. 具有有三个函数: #in ...
- python2.7入门---循环语句(while)
接下来就要了解循环语句了.我们都知道,程序在一般情况下是按顺序执行的.编程语言提供了各种控制结构,允许更复杂的执行路径.循环语句允许我们执行一个语句或语句组多次,下面是在大多数编程语言中的循环 ...
- linux ln 建立软链接-- 基于dubbo-zookeeper服务的 服务jar 引用公共的 lib
对于ln命令网上有很多的教程,这里不再复述, 其基本目的是:多个文件夹公用一个文件夹的里的文件. 其基本命令格式: ln [option] source_file dist_file (source_ ...
- cloudera manager服务迁移(scm数据库在postgresql上,其他amon,rman,oozie,metastore等在mysql上)
公司线上大数据集群,之前用的是公有云主机,现在换成了自己idc机房机器,需要服务迁移,已下为测试: 1.备份原postgresql数据库: pg_dump -U scm scm > scm.sq ...