原文链接www.cnblogs.com/zhouzhendong/p/UOJ220.html

前言

真是一道翔题。

草率题解

-1 的情况很好判,只有两种情况: n * m - c < 2 或者 n * m - c = 2 且两个格子相邻。

对于 x 坐标,我们大力将前两行、后两行、每一个点的上一行、所在行、下一行这些行离散化出来。

对于每一行,我们找出一些关键点,将一行分为若干段,将每一段看做一个点,上下左右相邻的段连边,跑Tarjan判割点。

怎么找关键点?对于每一个点,它左右距离2范围内,上下距离1 范围内的都拿出来就好了。

常数真大。

代码

#include <bits/stdc++.h>
#define clr(x) memset(x,0,sizeof x)
#define For(i,a,b) for (int i=(a);i<=(b);i++)
#define Fod(i,b,a) for (int i=(b);i>=(a);i--)
#define fi first
#define se second
#define pb(x) push_back(x)
#define mp(x,y) make_pair(x,y)
#define outval(x) cerr<<#x" = "<<x<<endl
#define outtag(x) cerr<<"---------------"#x"---------------"<<endl
#define outarr(a,L,R) cerr<<#a"["<<L<<".."<<R<<"] = ";\
For(_x,L,R)cerr<<a[_x]<<" ";cerr<<endl;
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> vi;
LL read(){
LL x=0,f=0;
char ch=getchar();
while (!isdigit(ch))
f|=ch=='-',ch=getchar();
while (isdigit(ch))
x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
return f?-x:x;
}
const int N=100010;
int T,n,m,c,s;
map <pair <int,int>,int> g;
int x[N],xx[N],y[N];
int dx[4]={ 0, 0, 1,-1};
int dy[4]={ 1,-1, 0, 0};
int Hx[N*3],cx,sum[N*3];
vector <int> Hy[N*3];
const int S=N*30;
vector <int> e[S];
int co[S];
void Add_Edge(int x,int y){
if (!co[x]&&!co[y])
e[x].pb(y),e[y].pb(x);
}
int dfn[S],low[S],Time;
int flag,cntroot=0,fir;
void Tarjan(int x,int pre){
dfn[x]=low[x]=++Time;
for (auto y : e[x])
if (!dfn[y]){
Tarjan(y,x);
low[x]=min(low[x],low[y]);
if (low[y]>=dfn[x]){
if (pre)
flag=1;
else
cntroot++;
}
}
else if (y!=pre)
low[x]=min(low[x],dfn[y]);
}
bool check1(int x,int y){
return 1<=x&&x<=n&&1<=y&&y<=m;
}
void Solve(){
n=read(),m=read(),c=read();
g.clear();
For(i,1,c){
x[i]=read(),y[i]=read();
g[mp(x[i],y[i])]=1;
}
if ((LL)n*m-c<=1)
return (void)puts("-1");
if ((LL)n*m-c==2){
For(i,1,n)
For(j,1,m)
if (!g[mp(i,j)])
For(k,0,3)
if (check1(i+dx[k],j+dy[k])&&!g[mp(i+dx[k],j+dy[k])])
return (void)puts("-1");
return (void)puts("0");
}
cx=0;
For(i,1,c){
if (x[i]>1)
Hx[++cx]=x[i]-1;
Hx[++cx]=x[i];
if (x[i]<n)
Hx[++cx]=x[i]+1;
}
Hx[++cx]=1,Hx[++cx]=n;
if (n>1)
Hx[++cx]=2,Hx[++cx]=n-1;
sort(Hx+1,Hx+cx+1);
cx=unique(Hx+1,Hx+cx+1)-Hx-1;
For(i,1,cx)
Hy[i].clear();
For(i,1,c){
xx[i]=lower_bound(Hx+1,Hx+cx+1,x[i])-Hx;
For(xp,xx[i]-1,xx[i]+1){
if (xp<1||xp>n)
continue;
For(yp,y[i]-1,y[i]+2)
if (1<=yp&&yp<=m)
Hy[xp].pb(yp);
}
}
sum[0]=1;
For(i,1,cx){
Hy[i].pb(1),Hy[i].pb(2),Hy[i].pb(m+1),Hy[i].pb(m);
sort(Hy[i].begin(),Hy[i].end());
Hy[i].resize(unique(Hy[i].begin(),Hy[i].end())-Hy[i].begin());
For(j,0,(int)Hy[i].size()-2)
co[sum[i-1]+j]=g[mp(Hx[i],Hy[i][j])];
sum[i]=sum[i-1]+(int)Hy[i].size()-1;
}
s=sum[cx]-1;
For(i,1,s)
e[i].clear();
For(i,1,cx)
For(j,0,(int)Hy[i].size()-3)
Add_Edge(sum[i-1]+j,sum[i-1]+j+1);
For(i,2,cx){
int p=0;
for (int j=0;j<=(int)Hy[i].size()-2;j++){
while (Hy[i-1][p+1]<=Hy[i][j])
p++;
while (p<(int)Hy[i-1].size()-1&&Hy[i-1][p+1]<=Hy[i][j+1]){
Add_Edge(sum[i-2]+p,sum[i-1]+j);
p++;
}
if (Hy[i-1][p]<Hy[i][j+1])
Add_Edge(sum[i-2]+p,sum[i-1]+j);
}
}
clr(dfn),clr(low);
fir=Time=flag=cntroot=0;
For(i,1,s){
if (co[i]||dfn[i])
continue;
if (!fir)
fir=i;
if (!dfn[i]&&i!=fir)
return (void)puts("0");
Tarjan(i,0);
}
flag|=cntroot>1;
puts(flag?"1":"2");
}
int main(){
T=read();
while (T--)
Solve();
return 0;
}

UOJ#220. 【NOI2016】网格 Tarjan的更多相关文章

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

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

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

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

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

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

  4. 洛谷P1173 [NOI2016]网格

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

  5. 【Codefoces487E/UOJ#30】Tourists Tarjan 点双连通分量 + 树链剖分

    E. Tourists time limit per test: 2 seconds memory limit per test: 256 megabytes input: standard inpu ...

  6. [Noi2016]网格

    来自FallDream的博客,未经允许,请勿转载,谢谢.   跳蚤国王和蛐蛐国王在玩一个游戏. 他们在一个 n 行 m 列的网格上排兵布阵.其中的 c 个格子中 (0≤c≤nm),每个格子有一只蛐蛐, ...

  7. BZOJ4651/UOJ220 [Noi2016]网格

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

  8. 并不对劲的bzoj4651:loj2084:uoj220:p1173:[NOI2016]网格

    题目大意 有一个\(n*m\)(\(n,m\leq10^9\))的网格,每个格子是空地或障碍(\(障碍数\leq10^5\)) 定义两块空地连通,当且仅当它们是"相邻的两块空地"或 ...

  9. BZOJ4651 NOI2016网格(割点)

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

随机推荐

  1. MySQL安装后的初始优化

    mysql数据库在安装之后,有一些内置的库(test库).用户(如root@localhost.localdomain)是不需要的,而且在Linux系统上,yum安装的mysql是默认无root密码的 ...

  2. html,css,js(包含简单的 ES6语法) 实现 简单的音乐盒

    知识要点 videoObject.load(): 加载某个视频(音频)文件,即重新播放 videoObject.play(): 播放视频(音频)文件 videoObject.remove(): 停止播 ...

  3. 几种常见的Preference总结

    DialogPreference共性 DialogPreference通用属性 说明 android:dialogIco 对话框的icon android:dialogLayout dialog的co ...

  4. Android 常用开源库总结(持续更新)

    前言 收集了一些比较常见的开源库,特此记录(已收录350+).另外,本文将持续更新,大家有关于Android 优秀的开源库,也可以在下面留言. 一 .基本控件 TextView HTextView 一 ...

  5. BIN文件合并烧写

    可以实现将Bootloader和Application合并烧写 使用UBIN.exe工具或者J-Flash工具 UBIN工具 选择Bootloader源文件 添加Bootloader源文件 选择App ...

  6. SpringBoot AOP概念及使用Demo

    AOP核心概念1.横切关注点 对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点2.切面(aspect)->(通知+切点) 类是对物体特征的抽象,切面就是对横切关注点的抽象.通知+切 ...

  7. 2013.6.22 - OpenNE第二天

    果然看中文材料就比较顺利,才半个小时就看完了一篇非常简单的综述<命名实体识别研究进展综述>(孙镇.王惠临).这个是2010年的文章,其实就是一个 科普文章,简述了国内外NER这块的历史如何 ...

  8. web workers 实例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. 代码重复检查工具——python的使用CPD比较好用,clone digger针对py2,其他有名的如Simian PMD-CPD CloneDR CCCD CCFinder Bauhaus CodePro

    代码重复检测: cpd --minimum-tokens 100 --files g:\source\python\ --language python >log.txt 输出类似: ===== ...

  10. K-means: 多次random initialization来避免bad局部最优

    K-means algorithm initialize K-means算法中有一步为随机初始化cluster centroids,这步如何进行,我们将介绍一种运行比较好的方法,这种方法比其它初始化的 ...