UOJ220 [NOI2016] 网格 【割顶】【并查集】
题目分析:
答案显然只有{-1,0,1,2}四种。
对于答案等于-1的情况,只有两种情况,一种是只剩一只跳蚤,另一种是只剩两只跳蚤且他们四连通,这个很好判。
对于答案等于0的情况,那说明联通块大于1,把图离散出来连边并查集判就可以了。
对于答案等于1的情况,我们要考虑唯一的联通块是否存在割顶,具体的,我们发现答案只可能是有蛐蛐的格子旁边的八个格子(n=1或m=1除外),那么把它们提取出来单独建点,而其它的离散,跑一边割顶就可以做了。
剩下的输出2.
代码:
#include<bits/stdc++.h>
using namespace std; const int maxn = ; int n,m,c,tot;
pair<int,int> pr[maxn];
vector<pair<int,int> > vec[maxn];
int arr[maxn],mlgb[maxn],isg[maxn];
vector<int> g[maxn];
int dx[]={,,,-,,-,,-};
int dy[]={,-,,,,-,-,};
int chk,pre[maxn];
int low[maxn],dfn[maxn],cl,fa[maxn]; void init(){
memset(pr,,sizeof(pr));
for(int i=;i<=tot;i++) low[i]=dfn[i]=fa[i]=isg[i]=arr[i]=;
for(int i=;i<=tot;i++) vec[i].clear(),g[i].clear();
cl = chk = n = m = c = tot = ;
} int found(int x){
int rx = x; while(pre[rx] != rx) rx = pre[rx];
while(pre[x] != rx){int tmp = pre[x]; pre[x] = rx; x = tmp;}
return rx;
} int pd0(){
sort(pr+,pr+c+);pr[] = make_pair(,m+);
int tnum = ,pnum = ;
int zt = ;
for(int i=;i<=c;i++) arr[++zt]=pr[i].first-,arr[++zt]=pr[i].first+,arr[++zt]=pr[i].first;
sort(arr+,arr+zt+); zt = unique(arr+,arr+zt+)-arr-;
while(arr[zt] == n+)zt--;
for(int i=;i<=zt;i++){
if(arr[i] == ) continue;
if(arr[i] != arr[i-]+){vec[++tnum].push_back(make_pair(,m));tot++;}
tnum++;
int lst = lower_bound(pr+,pr+c+,make_pair(arr[i]-,))-pr;
int now = lower_bound(pr+,pr+c+,make_pair(arr[i],))-pr;
if(pr[now].first != arr[i]) now = ;
int imp=;while(lst<=c&&pr[lst].first<=arr[i]+) mlgb[++imp]=pr[lst].second,lst++;
sort(mlgb+,mlgb+imp+); imp = unique(mlgb+,mlgb+imp+)-mlgb-;
int z = ;int j = now,k = ;
while(z <= m){
if(k > imp){vec[tnum].push_back(make_pair(z,m));tot++;z=m+;break;}
while(pr[j].first==arr[i]&&pr[j].second<mlgb[k])j++;
if(z < mlgb[k]-){vec[tnum].push_back(make_pair(z,mlgb[k]-));tot++;z = mlgb[k]-;}
if(z < mlgb[k]){isg[++tot]=;vec[tnum].push_back(make_pair(z,mlgb[k]-));z = mlgb[k];}
if(z==mlgb[k]&&(!(pr[j].first==arr[i]&&pr[j].second==mlgb[k]))){
isg[++tot]=;vec[tnum].push_back(make_pair(z,mlgb[k]));z = mlgb[k]+;
}else z = mlgb[k]+;
if(z > m) break;
while(pr[j].first==arr[i]&&pr[j].second<mlgb[k]+)j++;
if(!(pr[j].first==arr[i]&&pr[j].second==mlgb[k]+)){
isg[++tot]=;vec[tnum].push_back(make_pair(z,mlgb[k]+));z = mlgb[k]+;
}
k++;
}
}
if(arr[zt] != n){vec[++tnum].push_back(make_pair(,m));tot++;}
for(int i=;i<tot;i++) pre[i] = i;
for(int i=;i<tnum;i++){
int k = ;
for(int j=;j<vec[i].size();j++){
while(k<vec[i+].size()&&vec[i+][k].second < vec[i][j].first) k++;
while(k<vec[i+].size()&&vec[i+][k].second <= vec[i][j].second){
g[pnum+j].push_back(pnum+vec[i].size()+k);
g[pnum+vec[i].size()+k].push_back(pnum+j);
pre[found(pnum+j)] = found(pnum+vec[i].size()+k); k++;
}
if(k<vec[i+].size()&&vec[i+][k].first <= vec[i][j].second){
g[pnum+j].push_back(pnum+vec[i].size()+k);
g[pnum+vec[i].size()+k].push_back(pnum+j);
pre[found(pnum+j)] = found(pnum+vec[i].size()+k);
}
}
pnum += vec[i].size();
}
pnum = ;
for(int i=;i<=tnum;i++){
for(int j=;j<vec[i].size();j++){
if(vec[i][j].first == vec[i][j-].second+){
g[pnum+j].push_back(pnum+j-);
g[pnum+j-].push_back(pnum+j);
pre[found(pnum+j)] = found(pnum+j-);
}
}
pnum += vec[i].size();
}
int hh = ;
for(int i=;i<tot;i++){if(pre[i] == i) hh++;}
if(hh>) return ; else return ;
} void Tarjan(int now){
low[now] = dfn[now] = ++cl;
for(int i=;i<g[now].size();i++){
if(g[now][i] == fa[now]) continue;
if(dfn[g[now][i]] > dfn[now]) continue;
if(dfn[g[now][i]] == ){
fa[g[now][i]] = now;Tarjan(g[now][i]);
low[now] = min(low[now],low[g[now][i]]);
}else{low[now] = min(low[now],dfn[g[now][i]]);}
}
if(isg[now+]==)return;
if(now != ){
for(int i=;i<g[now].size();i++){
if(fa[g[now][i]] != now) continue;
if(low[g[now][i]] >= dfn[now]){chk=;}
}
}else{
int nh = ;
for(int i=;i<g[now].size();i++){if(fa[g[now][i]] == now){nh++;}}
if(nh > ) chk++;
}
} void read(){
scanf("%d%d%d",&n,&m,&c);
for(int i=;i<=c;i++){scanf("%d%d",&pr[i].first,&pr[i].second);}
} void work(){
if(1ll*n*m-c <= ){puts("-1");return;}
if(1ll*n*m-c == ){
sort(pr+,pr+c+); pair<int,int> l1,l2;
for(int i=;i<=n;i++) for(int j=;j<=m;j++){
int z = lower_bound(pr+,pr+c+,make_pair(i,j))-pr;
if(pr[z] == make_pair(i,j)) continue;
if(l1 != make_pair(,)) l2=make_pair(i,j); else l1=make_pair(i,j);
}
if(abs(l1.first-l2.first)+abs(l1.second-l2.second)==){puts("-1");}
else puts("");
return;
}
if(pd0()) {puts("");return;}
if(n == || m == ){puts("");return;}
Tarjan();
if(chk){puts("");return;}
else puts("");
} int main(){
int Tmp; scanf("%d",&Tmp);
while(Tmp--){
init();
read();
work();
}
return ;
}
UOJ220 [NOI2016] 网格 【割顶】【并查集】的更多相关文章
- 【XSY2741】网格 分治 LCT 并查集
题目描述 有一个\(n\times m\)的网格,线框的交点可以扭动,边不可伸缩.网格中有一些格子里面放了'x'形的支架,这些格子不会变形,但可以整体转动.如果所有格子都不能变形,那么称这个网格稳固. ...
- BZOJ4651/UOJ220 [Noi2016]网格
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- HDU 6081 度度熊的王国战略【并查集/数据弱水题/正解最小割算法】
链接6081 度度熊的王国战略 Time Limit: 40000/20000 MS (Java/Others) Memory Limit: 32768/132768 K (Java/Others) ...
- BZOJ4423 AMPPZ2013Bytehattan(并查集)
判断网格图中某两点是否被割开,可以将割边视为边区域视为点,转化为可切割这两点的区域是否连通.于是每次判断使两个区域连通后是否会形成环(边界视为连通),若是则说明被两点被割开.并查集维护. #inclu ...
- [UOJ#220][BZOJ4651][Noi2016]网格
[UOJ#220][BZOJ4651][Noi2016]网格 试题描述 跳蚤国王和蛐蛐国王在玩一个游戏. 他们在一个 n 行 m 列的网格上排兵布阵.其中的 c 个格子中 (0≤c≤nm),每个格子有 ...
- BZOJ_4423_[AMPPZ2013]Bytehattan_对偶图+并查集
BZOJ_4423_[AMPPZ2013]Bytehattan_对偶图+并查集 Description 比特哈顿镇有n*n个格点,形成了一个网格图.一开始整张图是完整的. 有k次操作,每次会删掉图中的 ...
- 图的生成树(森林)(克鲁斯卡尔Kruskal算法和普里姆Prim算法)、以及并查集的使用
图的连通性问题:无向图的连通分量和生成树,所有顶点均由边连接在一起,但不存在回路的图. 设图 G=(V, E) 是个连通图,当从图任一顶点出发遍历图G 时,将边集 E(G) 分成两个集合 T(G) 和 ...
- 【BZOJ-4423】Bytehattan 并查集 + 平面图转对偶图
4423: [AMPPZ2013]Bytehattan Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 144 Solved: 103[Submit][ ...
- 并查集 Union-Find
并查集能做什么? 1.连接两个对象; 2.查询两个对象是否在一个集合中,或者说两个对象是否是连接在一起的. 并查集有什么应用? 1. Percolation问题. 2. 无向图连通子图个数 3. 最近 ...
随机推荐
- Android常用优秀开源框架
Android常用优秀开源框架 https://github.com/Ericsongyl/AOSF AOSF:全称为Android Open Source Framework,即Android优秀开 ...
- 009 轮播图,offset系列
关于使用JS做轮播图,使用一个章节进行笔迹. 一:简单轮播图 1.程序 <!DOCTYPE html> <html lang="en"> <head& ...
- SynchronizedStack -- tomcat8同步栈
同步栈(安全栈): org.apache.tomcat.util.collections.SynchronizedStack通过stack栈锁来控制栈中获取的类T.通过push.pop和clear方法 ...
- pycharm怎么修改python路径
今天安装Django的时候遇到了python版本冲突,找不到python路径,所以又重新安装了一个python3.6.5 安装完之后,突然发现自己的pycharm是之前Anaconda的3.5版本,那 ...
- faster_rcnn mAP
- DateUtil 提供一些常用的时间想法的方法
package com.opslab.util; import java.text.ParseException;import java.text.SimpleDateFormat;import ja ...
- Swift4.0复习函数
1.函数的定义与调用: 一个函数定义的基本语法如以下代码所示: func function_name (param1: Int, param2: Float, param3: Double) -> ...
- top显示命令详解+top命令使用
http://blog.csdn.net/u014226549/article/details/22041289
- xray写POC踩坑
错误记录 静态文件目录不一定是static. 只考虑了linux的情况,如果是 windows 呢,能读取某些应用自己的源码吗. 实际环境参数不一定是id,thinkphp 不适合使用 poc 来写 ...
- Ubuntu与Window双系统安装的注意事项
UBUNTU与WINDOW双系统安装的注意事项 Ubuntu与Window双系统安装的注意事项 由 匿名 (未验证) 提交于 2019-05-18 10:07:41 登录 发表评论 29 次浏览 ...