题目大意

有一个\(n*m\)(\(n,m\leq10^9\))的网格,每个格子是空地或障碍(\(障碍数\leq10^5\))

定义两块空地连通,当且仅当它们是“相邻的两块空地”或“存在一块空地与这两块空地连通的两块空地”(也就是四连通)

求至少添加多少块障碍物,使存在两块空地不连通,或者输出-1表示无解

题解

当只有一块空地或只有两块相邻的空地时,无解

有解时,发现总能找到一个角落,使只用两个障碍物就能将这个角落和外界分开(如图)



也就是说,答案不超过2

当初始的障碍物已经将空地分成多个连通块时,答案为0

当存在一个点,把该点删去后空地会变成多个空地连通块时(割点),答案为1

以上两种都没有,答案为2

如果n*m比较小的话,就可以直接将每块空地与它上下左右的空地连边,判连通性,tarjan找割点

但是n,m都比较大,存不下,考虑上一种建图法中有哪些点是不必要的

连通性:

发现如果存在两个点不连通,那么一定存在两个不连通的点是被一个障碍物连通块隔开的

也就是说,可以通过判断“是否存在一个障碍物连通块,与它相邻的所有空地中,存在两块空地不连通”来判断整个图是否连通

具体地,先找出所有障碍物连通块,只把所有与这个连通块相邻(八连通)的空地互相连边,判断连通性

割点:

发现当网格的宽度不为1时,割点一定会与障碍相邻(1)

将不与障碍相邻的点删去后,剩下的点才可能成为割点,将这些点组成的图称为“图1”

但是这样建图后,会发现图中的割点可能会和它周围的没被加入图的空地相邻,导致它不是割点

那么就把与图1中的点相邻且不是障碍的点加入,得到图2,求图2是否有割点

根据(1),后加入的点在原图中一定不是割点,所以通过判断图2是否存在一个割点在图1中来判断原图是否有割点

代码
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register int i=(x);i<=(y);++i)
#define dwn(i,x,y) for(register int i=(x);i>=(y);--i)
#define view(u,k) for(int k=fir[u];k!=-1;k=nxt[k])
#define view2(u,k) for(int k=fir2[u];k!=-1;k=nxt2[k])
#define maxn 100010
#define maxnd 2500010
#define LL long long
#define maxm (maxnd<<2)
using namespace std;
int read()
{
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)&&ch!='-')ch=getchar();
if(ch=='-')f=-1,ch=getchar();
while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
return x*f;
}
void write(int x)
{
if(x==0){putchar('0'),putchar('\n');return;}
int f=0;char ch[20];
if(x<0)putchar('-'),x=-x;
while(x)ch[++f]=x%10+'0',x/=10;
while(f)putchar(ch[f--]);
putchar('\n');
return;
}
int t,n,m,c,qx[maxn],qy[maxn],tim,cnts,cntnd,pos[maxnd],sop[maxnd],sop2[maxnd],maxy;
int fir[maxnd],nxt[maxm],v[maxm],cnte,dfn[maxnd],low[maxnd],fa[maxnd],yes,stk[maxnd],tp;
int fir2[maxn],nxt2[maxn<<2],v2[maxn<<2],cnte2,cntnd2,vis2[maxn],vis[maxnd];
struct seq{int x,y,ad;}a[maxnd],b[maxn];
map<int,int>lft,up;
void ade(int u1,int v1){v[cnte]=v1,nxt[cnte]=fir[u1],fir[u1]=cnte++;}
void ade2(int u1,int v1){v2[cnte2]=v1,nxt2[cnte2]=fir2[u1],fir2[u1]=cnte2++;}
bool cmp1(seq x,seq y){return x.y==y.y?(x.x==y.x?x.ad<y.ad:x.x<y.x):x.y<y.y;}
int f(int x){return fa[x]<0?x:fa[x]=f(fa[x]);}
void merge(int x,int y){x=f(x),y=f(y);if(x==y)return;fa[x]+=fa[y],fa[y]=x;}
void tar(int u,int fa)
{
int in=0;
dfn[u]=low[u]=++tim;
view(u,k)
{
if(!dfn[v[k]])
{
tar(v[k],fa);
if(yes)return;
low[u]=min(low[u],low[v[k]]);
if(low[v[k]]>=dfn[u]&&u!=fa&&a[sop[u]].ad==1){yes=1;return;}
if(u==fa)in++;
}
low[u]=min(low[u],dfn[v[k]]);
}
if(u==fa&&in>=2&&a[sop[u]].ad==1){yes=1;return;}
}
int getr(int x,int y)
{
int l=1,r=cnts,ans=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(a[mid].x==x&&a[mid].y==y)ans=max(ans,mid),l=mid+1;
else if(a[mid].y<y||(a[mid].y==y&&a[mid].x<x))l=mid+1;
else r=mid-1;
}
return ans;
}
void getstk(int u)
{
vis2[u]=1;
int liml=max(1,a[sop2[u]].x-1),limr=min(n,a[sop2[u]].x+1),limd=max(1,a[sop2[u]].y-1),limu=min(m,a[sop2[u]].y+1);
rep(i,liml,limr)
rep(j,limd,limu)
{
int tmp=pos[getr(i,j)];
if(tmp&&!vis[tmp])stk[++tp]=tmp,vis[tmp]=1;
}
view2(u,k)if(!vis2[v2[k]])getstk(v2[k]);
return;
}
int jug()
{
int res=1;
rep(i,1,cntnd2)
{
tp=0;
if(!vis2[i])
{
getstk(i);
rep(j,1,tp)vis[stk[j]]=0;
rep(j,2,tp)if(f(stk[j])!=f(stk[1])){res=0;break;}
if(!res)break;
}
}
return res;
}
int main()
{
t=read();
while(t--)
{
n=read(),m=read(),c=read();cntnd=tim=cnts=cnte=yes=maxy=cntnd2=cnte2=0;
rep(i,1,c*25)fir[i]=fa[i]=-1,dfn[i]=sop[i]=pos[i]=0;lft.clear(),up.clear();
rep(i,1,c)
{
qx[i]=read(),qy[i]=read(),fir2[i]=-1,sop2[i]=vis2[i]=0;
int liml=max(1,qx[i]-2),limr=min(n,qx[i]+2),limd=max(1,qy[i]-2),limu=min(m,qy[i]+2);
rep(j,liml,limr)
rep(k,limd,limu)
{
a[++cnts].x=j,a[cnts].y=k,a[cnts].ad=min(2-abs(j-qx[i]),2-abs(k-qy[i]));
}
}
sort(a+1,a+cnts+1,cmp1);
int now=0;
rep(i,1,cnts)
{
if(i==cnts||(a[i].x!=a[i+1].x||a[i].y!=a[i+1].y))
{
if(a[i].ad==2)
{
int t1=up[a[i].y],t2=lft[a[i].x];cntnd2++;
up[a[i].y]=-cntnd2;lft[a[i].x]=-cntnd2;sop2[cntnd2]=i;
if(t1<0&&a[sop2[-t1]].x==a[i].x-1)ade2(-t1,cntnd2),ade2(cntnd2,-t1);
if(t2<0&&a[sop2[-t2]].y==a[i].y-1)ade2(-t2,cntnd2),ade2(cntnd2,-t2);
continue;
}
cntnd++;sop[cntnd]=i,pos[i]=cntnd;
int t1=up[a[i].y],t2=lft[a[i].x];up[a[i].y]=cntnd;lft[a[i].x]=cntnd;
if(t1>0)ade(t1,cntnd),ade(cntnd,t1),merge(t1,cntnd);
if(t2>0)ade(t2,cntnd),ade(cntnd,t2),merge(t2,cntnd);
}
}
int yeslink=jug();
if((LL)n*(LL)m<=2)write(-1);
else if(c==0)write(min(n,m)==1?1:2);
else if(cntnd==0)write(-1);
else if(!yeslink)write(0);
else if((LL)n*(LL)m-(LL)c<=2ll)write(-1);
else if(min(n,m)==1)write(1);
else
{
rep(i,1,cntnd){if(!dfn[i])tar(i,i);if(yes)break;}
if(yes)write(1);
else write(2);
}
}
return 0;
}

并不对劲的bzoj4651:loj2084:uoj220:p1173:[NOI2016]网格的更多相关文章

  1. BZOJ4651 & 洛谷1173 & UOJ220:[NOI2016]网格——题解(附debug数据)

    https://www.lydsy.com/JudgeOnline/problem.php?id=4651 https://www.luogu.org/problemnew/show/P1173#su ...

  2. 并不对劲的bzoj4651:loj2086:uoj222:p1712:[NOI2016]区间

    题目大意 有\(n\)(\(n\leq 5*10^5\))个闭区间\([L_1,R_1],[L_2,R_2],...,[L_n,R_n]\)(\(\forall i\in [1,n],0\leq L_ ...

  3. 洛谷P1173 [NOI2016]网格

    这个码量绝对是业界大毒瘤...... 300行,6.5k,烦的要死...... 题意:给你一个网格图,里面有0或1.你需要把一些0换成1使得存在某两个0不四联通.输出最小的换的数量.无解-1. n,m ...

  4. [UOJ#220][BZOJ4651][Noi2016]网格

    [UOJ#220][BZOJ4651][Noi2016]网格 试题描述 跳蚤国王和蛐蛐国王在玩一个游戏. 他们在一个 n 行 m 列的网格上排兵布阵.其中的 c 个格子中 (0≤c≤nm),每个格子有 ...

  5. BZOJ4651/UOJ220 [Noi2016]网格

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  6. BZOJ4651 NOI2016网格(割点)

    首先显然可以通过孤立角落里的跳蚤使其不连通,所以只要有解答案就不会大于2.同样显然的一点是当且仅当跳蚤数量<=2且连通时无解.做法其实也很显然了:特判无解,若跳蚤不连通输出0,否则看图中是否无割 ...

  7. [BZOJ4651][NOI2016]网格(Tarjan)

    下面直接给出结论,相关证明见官方题解. 1.若跳蚤数不超过1或仅有两只跳蚤且相邻,则答案为-1. 2.若跳蚤形成的连通块个数大于1,则答案为0. 3.若跳蚤之间建图存在割点,则答案为1. 4.否则为2 ...

  8. 并不对劲的bzoj4650:loj2083:uoj219:p1117:[NOI2016]优秀的拆分

    题目大意 "优秀的拆分"指将一个字符串拆分成AABB的形式 十次询问,每次给出一个字符串S(\(|S|\leq3*10^4\)),求它的所有子串的优秀的拆分的方案数之和 题解 此题 ...

  9. 并不对劲的bzoj4652:loj2085:uoj221:p1587:[NOI2016]循环之美

    题目大意 对于已知的十进制数\(n\)和\(m\),在\(k\)进制下,有多少个数值上互不相等的纯循环小数,可以用\(x/y\)表示,其中 \(1\leq x\leq n,1\leq y\leq m\ ...

随机推荐

  1. 【HTML/XML 3】XML 简介,来源

    导读:在标记语言出现之前,计算机中的数据一直都是以神秘的二进制在进行处理,但是,标记语言的出现,慢慢的改变了这种认识.那么,标记语言都经过了什么样的发展呢?它又有什么用处呢? 一.追根溯源(XML的产 ...

  2. C#静态构造函数和非静态构造函数

    // 使用静态构造函数时,需要注意几点 //1. 一个类中,最多只能有一个静态构造函数,不允许静态构造函数的重载: //2. 不能加任何访问修饰符(public/private/internale等) ...

  3. git clone, push, pull, fetch 的用法

    Git是目前最流行的版本管理系统,学会Git几乎成了开发者的必备技能. Git有很多优势,其中之一就是远程操作非常简便.本文详细介绍5个Git命令,它们的概念和用法,理解了这些内容,你就会完全掌握Gi ...

  4. delete NULL

    面试某公司的时候,某技术主管说你这delete前没有判断指针是否为NULL,当时我就…… 看来这是个传说中的好习惯,每当delete一个指针的时候,要先判断是不是NULL.比如: if ( p != ...

  5. Space Ant--poj1696(极角排序)

    http://poj.org/problem?id=1696 极角排序是就是字面上的意思   按照极角排序 题目大意:平面上有n个点然后有一只蚂蚁他只能沿着点向左走  求最多能做多少点 分析:  其实 ...

  6. 【nginx】【转】Nginx核心进程模型

    一.Nginx整体架构 正常执行中的nginx会有多个进程,最基本的有master process(监控进程,也叫做主进程)和woker process(工作进程),还可能有cache相关进程.   ...

  7. 【Nginx】如何使用http配置

    处理http配置项可以分为下面4个步骤: 1)创建数据结构用于存储配置项对应的参数 2)设定配置项在nginx.conf中出现时的限制条件与回调方法 3)实现第2步中的回调方法,或者使用Nginx框架 ...

  8. CentOS7 设置系统时间

    在CentOS 6版本,时间设置有date.hwclock命令, 硬件时钟和系统时钟 (1) 硬件时钟 RTC(Real-Time Clock)或CMOS时钟,一般在主板上靠电池供电,服务器断电后也会 ...

  9. 使用VLC搭建视频直播服务器

    去年我们信息之夜我们进行过视频直播服务,当时我们使用了WMS(Windows Media Server)实现了这个服务,但是编码是微软的WMV,因而像iPhone/Android这样的智能手机无法观看 ...

  10. HDOJ 4455 Substrings 递推+树状数组

    pre[i]第i位数往前走多少位碰到和它同样的数 dp[i]表示长度为i的子串,dp[i]能够由dp[i-1]加上从i到n的pre[i]>i-1的数减去最后一段长度为i-1的断中的不同的数得到. ...