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. 最近 ...
随机推荐
- WebSocket——SuperWebSocket实现服务端和客户端
WebSocket——SuperWebSocket实现服务端和客户端具体实现如下: 注:本作者是基于vs2019 enterprise版本,所有项目均为.Net Framwork4.7版本(因为Web ...
- keepalived vip removed with dhcp renewal【原创】
最近发现公司云平台服务器的vip有丢失的现象,查看keepalived日志 Jun :: lb1 dhclient: DHCPREQUEST of (xid=0x6deab016) Jun :: lb ...
- F12找到页面某一元素所绑定的点击事件
比如我要查看银行账号这个标签所绑定的事件. 操作过程中使用的是谷歌浏览器 第一步:在该元素上右键→检查 第二步:点击Event Listeners 这样就能看到该元素绑定的所有事件了 第三步:展开cl ...
- Mysql修改数据文件默认目录datadir
1.停止服务 service mysql stop service mysqld stopmysqladmin -uroot shutdown -p 2.创建目录 cd /data mkdir mys ...
- 关于postman与shiro权限验证问题
作为一个java的开发小白 , 写完一个web方法测试是必不可少的 , 只有测试号没问题的方法给别人时 ,别人才不知道你是小白 , 要不然很尴尬的 .新手入坑的测试工具是postman .这个工具用起 ...
- Flutter -------- dio网络请求
dio是Flutter中文网开源的一个强大的Dart Http请求库,支持Restful API.FormData.拦截器.请求取消.Cookie管理.文件上传/下载.超时等... 1.添加依赖# d ...
- openresty开发系列16--lua中的控制结构if-else/repeat/for/while
openresty开发系列16--lua中的控制结构if-else/repeat/for/while 一)条件 - 控制结构 if-else if-else 是我们熟知的一种控制结构.Lua 跟其他语 ...
- 【DataBase】Hsqldb的简单使用
介绍 HSQLDB是一个开放源代码的JAVA数据库,其具有标准的SQL语法和JAVA接口,它可以自由使用和分发,非常简洁和快速的.具有Server模式,每个程序需要不同的命令来运行. HyperSQL ...
- matlab基本数据结构struct
一起来学演化计算-matlab基本数据结构struct 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考文献 http://blog.sina.com.cn/s/blog_46865140 ...
- Flink统计当日的UV、PV
Flink 统计当日的UV.PV 测试环境: flink 1.7.2 1.数据流程 a.模拟数据生成,发送到kafka(json 格式) b.flink 读取数据,count c. 输出数据到kafk ...