UOJ220 [NOI2016] 网格 【割顶】【并查集】
题目分析:
答案显然只有{-1,0,1,2}四种。
对于答案等于-1的情况,只有两种情况,一种是只剩一只跳蚤,另一种是只剩两只跳蚤且他们四连通,这个很好判。
对于答案等于0的情况,那说明联通块大于1,把图离散出来连边并查集判就可以了。
对于答案等于1的情况,我们要考虑唯一的联通块是否存在割顶,具体的,我们发现答案只可能是有蛐蛐的格子旁边的八个格子(n=1或m=1除外),那么把它们提取出来单独建点,而其它的离散,跑一边割顶就可以做了。
剩下的输出2.
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 2012000; 5 6 int n,m,c,tot; 7 pair<int,int> pr[maxn]; 8 vector<pair<int,int> > vec[maxn]; 9 int arr[maxn],mlgb[maxn],isg[maxn]; 10 vector<int> g[maxn]; 11 int dx[8]={0,0,1,-1,1,-1,1,-1}; 12 int dy[8]={1,-1,0,0,1,-1,-1,1}; 13 int chk,pre[maxn]; 14 int low[maxn],dfn[maxn],cl,fa[maxn]; 15 16 void init(){ 17 memset(pr,0,sizeof(pr)); 18 for(int i=0;i<=tot;i++) low[i]=dfn[i]=fa[i]=isg[i]=arr[i]=0; 19 for(int i=0;i<=tot;i++) vec[i].clear(),g[i].clear(); 20 cl = chk = n = m = c = tot = 0; 21 } 22 23 int found(int x){ 24 int rx = x; while(pre[rx] != rx) rx = pre[rx]; 25 while(pre[x] != rx){int tmp = pre[x]; pre[x] = rx; x = tmp;} 26 return rx; 27 } 28 29 int pd0(){ 30 sort(pr+1,pr+c+1);pr[0] = make_pair(0,m+10); 31 int tnum = 0,pnum = 0; 32 int zt = 0; 33 for(int i=1;i<=c;i++) arr[++zt]=pr[i].first-1,arr[++zt]=pr[i].first+1,arr[++zt]=pr[i].first; 34 sort(arr+1,arr+zt+1); zt = unique(arr+1,arr+zt+1)-arr-1; 35 while(arr[zt] == n+1)zt--; 36 for(int i=1;i<=zt;i++){ 37 if(arr[i] == 0) continue; 38 if(arr[i] != arr[i-1]+1){vec[++tnum].push_back(make_pair(1,m));tot++;} 39 tnum++; 40 int lst = lower_bound(pr+1,pr+c+1,make_pair(arr[i]-1,0))-pr; 41 int now = lower_bound(pr+1,pr+c+1,make_pair(arr[i],0))-pr; 42 if(pr[now].first != arr[i]) now = 0; 43 int imp=0;while(lst<=c&&pr[lst].first<=arr[i]+1) mlgb[++imp]=pr[lst].second,lst++; 44 sort(mlgb+1,mlgb+imp+1); imp = unique(mlgb+1,mlgb+imp+1)-mlgb-1; 45 int z = 1;int j = now,k = 1; 46 while(z <= m){ 47 if(k > imp){vec[tnum].push_back(make_pair(z,m));tot++;z=m+1;break;} 48 while(pr[j].first==arr[i]&&pr[j].second<mlgb[k])j++; 49 if(z < mlgb[k]-1){vec[tnum].push_back(make_pair(z,mlgb[k]-2));tot++;z = mlgb[k]-1;} 50 if(z < mlgb[k]){isg[++tot]=1;vec[tnum].push_back(make_pair(z,mlgb[k]-1));z = mlgb[k];} 51 if(z==mlgb[k]&&(!(pr[j].first==arr[i]&&pr[j].second==mlgb[k]))){ 52 isg[++tot]=1;vec[tnum].push_back(make_pair(z,mlgb[k]));z = mlgb[k]+1; 53 }else z = mlgb[k]+1; 54 if(z > m) break; 55 while(pr[j].first==arr[i]&&pr[j].second<mlgb[k]+1)j++; 56 if(!(pr[j].first==arr[i]&&pr[j].second==mlgb[k]+1)){ 57 isg[++tot]=1;vec[tnum].push_back(make_pair(z,mlgb[k]+1));z = mlgb[k]+2; 58 } 59 k++; 60 } 61 } 62 if(arr[zt] != n){vec[++tnum].push_back(make_pair(1,m));tot++;} 63 for(int i=0;i<tot;i++) pre[i] = i; 64 for(int i=1;i<tnum;i++){ 65 int k = 0; 66 for(int j=0;j<vec[i].size();j++){ 67 while(k<vec[i+1].size()&&vec[i+1][k].second < vec[i][j].first) k++; 68 while(k<vec[i+1].size()&&vec[i+1][k].second <= vec[i][j].second){ 69 g[pnum+j].push_back(pnum+vec[i].size()+k); 70 g[pnum+vec[i].size()+k].push_back(pnum+j); 71 pre[found(pnum+j)] = found(pnum+vec[i].size()+k); k++; 72 } 73 if(k<vec[i+1].size()&&vec[i+1][k].first <= vec[i][j].second){ 74 g[pnum+j].push_back(pnum+vec[i].size()+k); 75 g[pnum+vec[i].size()+k].push_back(pnum+j); 76 pre[found(pnum+j)] = found(pnum+vec[i].size()+k); 77 } 78 } 79 pnum += vec[i].size(); 80 } 81 pnum = 0; 82 for(int i=1;i<=tnum;i++){ 83 for(int j=1;j<vec[i].size();j++){ 84 if(vec[i][j].first == vec[i][j-1].second+1){ 85 g[pnum+j].push_back(pnum+j-1); 86 g[pnum+j-1].push_back(pnum+j); 87 pre[found(pnum+j)] = found(pnum+j-1); 88 } 89 } 90 pnum += vec[i].size(); 91 } 92 int hh = 0; 93 for(int i=0;i<tot;i++){if(pre[i] == i) hh++;} 94 if(hh>1) return 1; else return 0; 95 } 96 97 void Tarjan(int now){ 98 low[now] = dfn[now] = ++cl; 99 for(int i=0;i<g[now].size();i++){ 100 if(g[now][i] == fa[now]) continue; 101 if(dfn[g[now][i]] > dfn[now]) continue; 102 if(dfn[g[now][i]] == 0){ 103 fa[g[now][i]] = now;Tarjan(g[now][i]); 104 low[now] = min(low[now],low[g[now][i]]); 105 }else{low[now] = min(low[now],dfn[g[now][i]]);} 106 } 107 if(isg[now+1]==0)return; 108 if(now != 0){ 109 for(int i=0;i<g[now].size();i++){ 110 if(fa[g[now][i]] != now) continue; 111 if(low[g[now][i]] >= dfn[now]){chk=1;} 112 } 113 }else{ 114 int nh = 0; 115 for(int i=0;i<g[now].size();i++){if(fa[g[now][i]] == now){nh++;}} 116 if(nh > 1) chk++; 117 } 118 } 119 120 void read(){ 121 scanf("%d%d%d",&n,&m,&c); 122 for(int i=1;i<=c;i++){scanf("%d%d",&pr[i].first,&pr[i].second);} 123 } 124 125 void work(){ 126 if(1ll*n*m-c <= 1){puts("-1");return;} 127 if(1ll*n*m-c == 2){ 128 sort(pr+1,pr+c+1); pair<int,int> l1,l2; 129 for(int i=1;i<=n;i++) for(int j=1;j<=m;j++){ 130 int z = lower_bound(pr+1,pr+c+1,make_pair(i,j))-pr; 131 if(pr[z] == make_pair(i,j)) continue; 132 if(l1 != make_pair(0,0)) l2=make_pair(i,j); else l1=make_pair(i,j); 133 } 134 if(abs(l1.first-l2.first)+abs(l1.second-l2.second)==1){puts("-1");} 135 else puts("0"); 136 return; 137 } 138 if(pd0()) {puts("0");return;} 139 if(n == 1 || m == 1){puts("1");return;} 140 Tarjan(0); 141 if(chk){puts("1");return;} 142 else puts("2"); 143 } 144 145 int main(){ 146 int Tmp; scanf("%d",&Tmp); 147 while(Tmp--){ 148 init(); 149 read(); 150 work(); 151 } 152 return 0; 153 }
转载于:https://www.cnblogs.com/Menhera/p/10799316.html
UOJ220 [NOI2016] 网格 【割顶】【并查集】相关推荐
- 并查集(Union-Find)
并查集(Union-Find) 并查集(Union-Find) 1.初始化 2.查询 3.合并 4.平衡性优化,扁平化 5.按秩合并 6.路径压缩 7.代码 常用模板 [★ 547. 省份数量](ht ...
- 图 相关算法~从头学算法【广搜、 深搜、 拓扑排序、 并查集、 弗洛伊德算法、迪杰斯特拉算法】
图的相关主流算法主要有: 广度优先搜索 深度优先搜索 拓扑排序 并查集 多源最短路径(弗洛伊德算法) 单源最短路径(迪杰斯特拉算法) 其中呢,最基本的是前两种,也就是平时常用的广搜和深搜,本文中将概要 ...
- NOIp 数据结构专题总结 (1):STL、堆、并查集、ST表、Hash表
系列索引: NOIp 数据结构专题总结 (1) NOIp 数据结构专题总结 (2) STL structure std::vector #include <vector> std::vec ...
- 并查集 - 交换字符串中的元素
题目链接 用并查集维护相互可以交换的索引,然后同一并查集上的字符放到小顶堆,每次取堆顶的字符重构字符串. class Solution {public:string smallestStringWit ...
- 并查集路径压缩_并查集(UnionFind)技巧总结
什么是并查集 在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题.有一个联合-查找算法(Union-find Algorithm)定义了两个用 ...
- CF461D-Appleman and Complicated Task【并查集】
正题 题目链接:https://www.luogu.com.cn/problem/CF461D 题目大意 n∗nn*nn∗n的网格需要填上xxx或ooo,其中有kkk个格子已经固定,求有多少中填写方案 ...
- codeforces gym-101736 Farmer Faul 平衡树+并查集
题目 题目链接 题意 给出nnn个整数,其中1≤n≤106" role="presentation" style="position: relative;&qu ...
- [BZOJ4537][Hnoi2016]最小公倍数 奇怪的分块+可撤销并查集
4537: [Hnoi2016]最小公倍数 Time Limit: 40 Sec Memory Limit: 512 MB Submit: 1474 Solved: 521 [Submit][St ...
- 经典算法题:字典树、并查集、单调栈、二分、带标记函数dp、树、全排列、字符串问题等常用算法
0. Tips 1. 位运算 如何枚举一个二进制状态数字k的子集, 方法就是针对中的二进制为1的位开始进行减法,判断数字k的二进制子集, 像枚举(2^k-1) ~ 0一样枚举其子集: int sub ...
- [Leedcode][JAVA][第200题][岛屿数量][DFS][BFS][并查集]
[问题描述] 第200题 岛屿数量 给你一个由 '1'(陆地)和 '0'(水)组成的的二维网格,请你计算网格中岛屿的数量.岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成 ...
最新文章
- python---简单的接口测试实例
- 历年计算机一级考试题库及答案,全国计算机一级考试试题库及答案
- 调整 W600 PWM的输出频率
- android布局如何空行,借用你的思路和框架,修复了空行、偶尔setText无效、padding设置的bug...
- linux 更改mysql的数据库目录
- “宝藏”大会NVIDIA GTC Digital来袭!这些AI前沿课程不容错过
- Spring Cloud Gateway介绍(一)
- jsplumb拖线_基于jsplumb插件制作可拖拽、保存流程图、重绘保存后的流程图总结...
- c语言popen函数多线程,关于多线程:多线程环境中的Python-Subprocess-Popen行为不一致...
- Java回调机制总结
- 万用表怎么测量电池容量_万用表如何测量电池容量?
- OSChina 娱乐弹弹弹——周一至周五,汗滴禾下土
- 计算机专业就业尴尬问题,计算机专业就业困境初探
- JavaMail实现发送邮件程序
- emoji表情mysql报错_MySql存储emoji表情报错的处理方法
- 通过Tomtit实现Perl6开发工作流程的自动化
- 免费无限大文件存储网盘 -- send.cm!必须收藏!操作简单,国内外都能访问,不用注册或下载,支持FTP,还带API,页面还简洁,真的爱了~
- VxWorks下 canOpen移植心得 stm32 - ppc
- 央视:乐视网是创业失败还是涉嫌欺诈?
- 基于NB-IoT的智慧路灯监控系统(NB-IoT专栏—实战篇5:手机应用开发)