Gym - 101550A Artwork (并查集在线做法)
题意:给你一个n*m的网格图,初始时格点全白,每次可以将一段连续的格点涂黑。求出每次操作之后白色连通块的数量。
看了看网上的题解,基本全是离线的做法。其实这道题是有在线的做法的,利用了对偶图的性质,适用于任意平面图(大概是)。
(ps:本题思路是我受thu叉院神犇wzf在wannafly冬令营上提到的对偶图思想的启发而想出来的,先膜为敬~~)
我们可以反过来考虑黑格的连通性。假如我们在涂黑某个格点的时候,把两个分离的黑格“连了起来”,这时有两种可能的情况:
1.两黑格在同一连通分量。此时如果将两黑格连接,必将形成一个回路,并且产生一个新的白色连通块。(回路中包着的区域就是一个白色连通块)
2.两黑格不在同一连通分量。此时将两黑格连接不会形成回路,因而也不会产生新的白色连通块。
注意:
1.白格是四连通的,因此对偶图中的黑格应当是八连通的。
2.上面的“连通分量”指的是外侧的连通分量,而不是内侧的连通分量。
例如,假如我们面临下面的状况:

此时,黑格3,4,5已经相连,因此需要把它们看成一个整体,而1,2各自分离,需要单独考虑。我们试图将中间的白色格子涂黑,假设1,2,3,4,5在外侧区域同属于一个连通块,那么中间的白色连通块数量将由原来的一个拆分成3个,分别夹在(1,2),(1,3)和(2,5)之间。
因此我们可以总结出规律:把与中间格点相邻的8个格子中所有的黑格按照顺时针或者逆时针顺序排成一列,把相互八连通的格子放在同一个内侧连通分量中(这个过程可以用另一个并查集实现)。我们把内侧连通分量不同的两个相邻格子两两合并,如果两个格子恰好在外侧同属于一个连通分量,那么必将多出一个“包起来”的白色连通块,此时答案+1。
注意将最后一个连通分量与第一个连通分量合并时不要计算对答案的贡献,因为合并后,原来中间的白色连通块就“消失”了,而它不应该消失,为了不让它消失,需要把这个连通块归结到一个未合并的连通区域中,因此需要保留一个白色连通区域作为原来中间白色连通块的新的“归属”。
最后需要注意的就是如果中间的白格的上下左右四个方向都是黑格,此时中间的白格单独属于一个连通块,在涂黑之后不能归结到任何一个区域,直接就消失了,此时答案应当-1。
还有就是在初始时应当把网格的四周涂黑,简化判断。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+;
const int dx[]= {-,,,,,,-,-};
const int dy[]= {-,-,-,,,,,};
int n,m,nq,fa[N*N],qx[],qy[],fa2[],n2,ans,a[N][N];
int fd(int x,int* fa) {return ~fa[x]?fa[x]=fd(fa[x],fa):x;}
bool mg(int x,int y,int* fa) {
int fx=fd(x,fa),fy=fd(y,fa);
if(fx==fy)return ;
else {fa[fx]=fy; return ;}
}
bool adj(int x1,int y1,int x2,int y2) {//判断是否8连通
return abs(x1-x2)+abs(y1-y2)==||(abs(x1-x2)==&&abs(y1-y2)==);
}
int id(int x,int y) {return x*(m+)+y;}//给格点标号
void solve(int x,int y) {
if(a[x][y])return;
a[x][y]=,n2=;
for(int i=; i<; ++i) {
int xx=x+dx[i],yy=y+dy[i];
if(a[xx][yy])qx[n2]=xx,qy[n2++]=yy;
}//把周围相邻的黑格按顺序扒出来
for(int i=; i<n2; ++i)fa2[i]=-;
for(int i=; i<n2; ++i)
if(adj(qx[i],qy[i],qx[(i+)%n2],qy[(i+)%n2]))mg(i,(i+)%n2,fa2);//合并内侧相邻黑格
for(int i=; i<n2-; ++i)
if(fd(i,fa2)!=fd(i+,fa2)&&fd(i+,fa2)!=fd(,fa2)
&&!mg(id(qx[i],qy[i]),id(qx[i+],qy[i+]),fa))++ans;//如果内侧不连通的黑格在外侧连通,则答案+1
if(a[x][y-]&&a[x][y+]&&a[x-][y]&&a[x+][y])--ans;//中间的格子被包围,答案-1
if(n2)mg(id(qx[],qy[]),id(x,y),fa);//将周围的黑格与中间的格子合并
} int main() {
scanf("%d%d%d",&n,&m,&nq);
memset(fa,-,sizeof fa);
for(int i=; i<=n+; ++i)a[i][]=a[i][m+]=,fa[id(i,)]=fa[id(i,m+)]=;
for(int i=; i<=m+; ++i)a[][i]=a[n+][i]=,fa[id(,i)]=fa[id(n+,i)]=;//将边界格子涂黑并放在同一个连通块
fa[]=-,ans=;
while(nq--) {
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(x1<x2) for(int i=x1; i<=x2; ++i)solve(i,y1);
else for(int i=y1; i<=y2; ++i)solve(x1,i);
printf("%d\n",ans);
}
return ;
}
Gym - 101550A Artwork (并查集在线做法)的更多相关文章
- Artwork Gym - 101550A 离线并查集
题目:题目链接 思路:每个空白区域当作一个并查集,因为正着使用并查集分割的话dfs会爆栈,判断过于复杂也会导致超时,我们采用离线反向操作,先全部涂好,然后把黑格子逐步涂白,我们把每个空白区域当作一个并 ...
- Codeforces Gym 100463E Spies 并查集
Spies Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100463/attachments Desc ...
- Gym - 100676F Palindrome —— 并查集
题目链接:https://vjudge.net/contest/155789#problem/E 题解: 由于是回文串,所以可以先将在对称位置的字符放在同一个集合(如果期间有两个非‘?’,且不相等,则 ...
- POJ1703 && POJ2942 &&POJ 1182 并查集 这个做法挺巧妙
Find them, Catch them Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 37242 Accepted: ...
- 2019-2020 ACM-ICPC Brazil Subregional Programming Contest Problem A Artwork (并查集)
题意:有一个矩形,有\(k\)个警报器,警报器所在半径\(r\)内不能走,问是否能从左上角走到右下角. 题解:用并查集将所有相交的圆合并,那么不能走的情况如下图所示 所以最后查询判断一下即可. 代码: ...
- UVALive 6910 Cutting Tree(并查集应用)
总体来说,这个题给的时间比较长,样例也是比较弱的,别的方法也能做出来. 我第一次使用的是不合并路径的并查集,几乎是一种暴力,花了600多MS,感觉还是不太好的,发现AC的人很多都在300MS之内的过得 ...
- 还是畅通工程(hdu1233)并查集应用
还是畅通工程 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Sub ...
- 【bzoj4998】星球联盟(并查集+边双)
题面 传送门 题解 总算有自己的\(bzoj\)账号啦! 话说这题好像\(Scape\)去年暑假就讲过--然而我到现在才会-- \(LCT\)什么的跑得太慢了而且我也不会,所以这里是一个并查集的做法 ...
- BZOJ 4516: [Sdoi2016]生成魔咒——后缀数组、并查集
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4516 题意 一开始串为空,每次往串后面加一个字符,求本质不同的子串的个数,可以离线.即长度为 ...
随机推荐
- Qt5_qt.conf
本站所有文章由本站和原作者保留一切权力,仅在保留本版权信息.原文链接.原 文作者的情况下允许转载,转载请勿删改原文内容, 并不得用于商业用途. 谢谢合作. 原文链接:用qt.conf和qtconfig ...
- Android TableLayout中的使用说明
TableLayout特点: 1)TableLayout和我们平时在网页上见到的Table有所不同,TableLayout没有边框的 2)它是由多个TableRow对象组成,每个TableRow可以有 ...
- RabbitMQ入门_12_发布方确认
参考资料:https://www.rabbitmq.com/confirms.html 通过 ack 机制,我们可以确保队列中的消息一定能被消费到.那我们有办法保证消息发布方一定把消息发送到队列了吗? ...
- 二分检索函数lower_bound()和upper_bound()
二分检索函数lower_bound()和upper_bound() 一.说明 头文件:<algorithm> 二分检索函数lower_bound()和upper_bound() lower ...
- Java基础十一--多态
Java基础十一--多态 一.多态定义 简单说:就是一个对象对应着不同类型. 多态在代码中的体现: 父类或者接口的引用指向其子类的对象. /* 对象的多态性. class 动物 {} class 猫 ...
- 30 进程process
进程模块 process Process([group [, target [, name [, args [, kwargs]]]]]),由该类实例化得到的对象,表示一个子进程中的任务(尚未启动) ...
- UVA-10710 Skyscraper Floors (找规律+幂取模)
题目大意:题目中给了一种数的定义,根据定义,让判断一个给定的数是不是这种数.题中叫这种数为吉米数,定义如下:对序列1,2,3,,,,n,做n-1次SF变换(对该变换的解释在下文),如果能得到原序列,则 ...
- 第 4 章—— C# 语言特性(《精通 ASP.NET MVC 5》)
这里只提供各个特性的简单概括. C# 的完整指南可参阅<Introducing Visual C#>.深度了解 LINQ 可参考<Pro LINQ in C#> 4.1 准备示 ...
- java使用HttpClient
HttpClient常用的包有两个 org.apache.http.client以及org.apache.commons.httpclient 我常用的是org.apache.http.client. ...
- 一、重写(覆盖)override
一.重写(覆盖)override 子类可以继承父类对象的方法,在继承后,重复提供该方法,就叫做方法的重写,又叫做覆盖override package property; //父类对象 public c ...