题目链接

题意:给你一个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 (并查集在线做法)的更多相关文章

  1. Artwork Gym - 101550A 离线并查集

    题目:题目链接 思路:每个空白区域当作一个并查集,因为正着使用并查集分割的话dfs会爆栈,判断过于复杂也会导致超时,我们采用离线反向操作,先全部涂好,然后把黑格子逐步涂白,我们把每个空白区域当作一个并 ...

  2. Codeforces Gym 100463E Spies 并查集

    Spies Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100463/attachments Desc ...

  3. Gym - 100676F Palindrome —— 并查集

    题目链接:https://vjudge.net/contest/155789#problem/E 题解: 由于是回文串,所以可以先将在对称位置的字符放在同一个集合(如果期间有两个非‘?’,且不相等,则 ...

  4. POJ1703 && POJ2942 &&POJ 1182 并查集 这个做法挺巧妙

    Find them, Catch them Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 37242   Accepted: ...

  5. 2019-2020 ACM-ICPC Brazil Subregional Programming Contest Problem A Artwork (并查集)

    题意:有一个矩形,有\(k\)个警报器,警报器所在半径\(r\)内不能走,问是否能从左上角走到右下角. 题解:用并查集将所有相交的圆合并,那么不能走的情况如下图所示 所以最后查询判断一下即可. 代码: ...

  6. UVALive 6910 Cutting Tree(并查集应用)

    总体来说,这个题给的时间比较长,样例也是比较弱的,别的方法也能做出来. 我第一次使用的是不合并路径的并查集,几乎是一种暴力,花了600多MS,感觉还是不太好的,发现AC的人很多都在300MS之内的过得 ...

  7. 还是畅通工程(hdu1233)并查集应用

    还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Sub ...

  8. 【bzoj4998】星球联盟(并查集+边双)

    题面 传送门 题解 总算有自己的\(bzoj\)账号啦! 话说这题好像\(Scape\)去年暑假就讲过--然而我到现在才会-- \(LCT\)什么的跑得太慢了而且我也不会,所以这里是一个并查集的做法 ...

  9. BZOJ 4516: [Sdoi2016]生成魔咒——后缀数组、并查集

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4516 题意 一开始串为空,每次往串后面加一个字符,求本质不同的子串的个数,可以离线.即长度为 ...

随机推荐

  1. 记录一个错误,在bundle install时候出现 shoulda-mathcers bundle install fails with git error

    复制粘体错误到google.找到解决方案: https://github.com/thoughtbot/shoulda-matchers/issues/1057 GIT remote: https:/ ...

  2. log4j配置文件位置详解

    自动加载配置文件: (1)如果采用log4j输出日志,要对log4j加载配置文件的过程有所了解.log4j启动时,默认会寻找source folder下的log4j.xml配置文件,若没有,会寻找lo ...

  3. pageContext对象

    pageContext对象是JSP中很重要的一个内置对象; 1.pageContext对象存取其他隐含对象属性的方法,此时需要指定范围的参数. getAttribute(String name):取得 ...

  4. python 使用yield进行数据的流式处理

    demo:从文件中取包含字符“a”的5行数据做一次批处理!!! # coding: utf-8 import time def cat(f): for line in f: yield line de ...

  5. tensorflow安装相关问题

    安装步骤 要求:Python必须是64位根据TensorFlow的计算方式,TensorFlow的安装分为CPU版本和GPU版本对于Python3.5或者Python3.6,可以使用pip insta ...

  6. hadoop hadoop install (1)

    vmuser@vmuser-VirtualBox:~$ sudo useradd -m hadoop -s /bin/bash[sudo] vmuser 的密码: vmuser@vmuser-Virt ...

  7. [C#]C#彩色扭曲验证码

    该验证码生成类集合了网上大部分的验证码生成类的精华,博采众长并多次改进,现在已经形成了可在生产环节中使用的验证码. 该验证码加入了背景噪点,背景噪点曲线和直线,背景噪点文字以及扭曲,调暗,模糊等.完全 ...

  8. H5技术干货

    H5技术干货 meta标签相关知识 H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 <meta name="viewport" content="width=d ...

  9. windows下运用批处理实现一键自动开启多个应用

    工作时,我每天早上到公司,打开自己的电脑,都会有几个固定的软件(myeclipse,飞信,firefox,foxmail等).文件夹和文件需要打开,每天如此,感到很烦,浪费时间做重复的工作,于是想到一 ...

  10. Python Threading多线程简单例子

    业务监控,多线程例子,实现每类个监控项的不同监控间隔. #coding=utf-8import sysimport pymysqlimport osfrom prometheus_client imp ...