正题

题目链接:https://www.luogu.com.cn/problem/P7295


题目大意

给出\(n*m\)的网格,每个格子上有字母,相同字母的四联通相邻格子为连通,每次询问一个子矩阵求连通块个数。

\(1\leq n,m,q\leq 1000\)


解题思路

首先一张连通的平面图有欧拉公式

\[V+F=E+2
\]

其中\(V,E,F\)分别表示点数,边数,区域个数(对偶图点数)。

然后不连通的对偶图会共用一个无界域,设为\(C\)个连通块,无界域会重复统计\(C-1\)次,然后联立得

\[V+F-E=C+1
\]

然后考虑怎么用这个求,首先是\(V,E\),这个很容易搞,\(V\)直接计算,\(E\)用二维前缀和算就好了。

主要是\(F\)怎么搞,先构出不严格的对偶图(就是每个格子边上的点当做点),然后\(F\)就是对偶图的连通块数。

对于整张图的每个连通块,我们选择任意一个点标记,然后记录每个点对应连通块的标记点,然后直接二维前缀和统计连通块内的标记点个数,然后枚举边界减去边上不完整被统计的的连通块最后加上无界域就好了。

时间复杂度\(O(nm+q(n+m))\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1100;
const int dx[4]={1,-1,0,0},dy[4]={0,0,1,-1};
int n,m,q,E[2][N][N],mx[N][N],my[N][N],F[N][N];
char s[N][N];bool v[N][N];
bool edg(int x,int y,int zx,int zy){
if(zx<0||zy<0||zx>n||zy>m)return 0;
if(zx>0&&zx<n&&zy==y+1)return (s[x][y+1]!=s[x+1][y+1]);
if(zx>0&&zx<n&&zy==y-1)return (s[x][y]!=s[x+1][y]);
if(zy>0&&zy<m&&zx==x+1)return (s[x+1][y]!=s[x+1][y+1]);
if(zy>0&&zy<m&&zx==x-1)return (s[x][y]!=s[x][y+1]);
return 1;
}
void dfs(int x,int y){
if(x==1&&y==4)
x++,x--;
if(v[x][y])return;v[x][y]=1;
for(int k=0;k<4;k++){
int zx=x+dx[k],zy=y+dy[k];
if(edg(x,y,zx,zy)){
mx[zx][zy]=mx[x][y];
my[zx][zy]=my[x][y];
dfs(zx,zy);
}
}
return;
}
#define Get(F,x1,y1,x2,y2) (F[x2][y2]-((x1)?F[x1-1][y2]:0)-((y1)?F[x2][y1-1]:0)+(((x1)&&(y1))?F[x1-1][y1-1]:0))
int check(int x,int y,int x1,int y1,int x2,int y2){
if(!v[x][y]&&x>=x1&&x<=x2&&y>=y1&&y<=y2)
{v[x][y]=1;return 1;}
return 0;
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=n;i++)
scanf("%s",s[i]+1);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
E[0][i][j]=E[0][i-1][j]+E[0][i][j-1]-E[0][i-1][j-1];
E[1][i][j]=E[1][i-1][j]+E[1][i][j-1]-E[1][i-1][j-1];
if(s[i][j]==s[i][j+1])E[0][i][j]++;
if(s[i][j]==s[i+1][j])E[1][i][j]++;
}
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
if(!v[i][j]){
mx[i][j]=i;my[i][j]=j;
F[i][j]++;dfs(i,j);
}
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
F[i][j]+=(i?F[i-1][j]:0)+(j?F[i][j-1]:0)-((i&&j)?F[i-1][j-1]:0);
memset(v,0,sizeof(v));
while(q--){
int x1,y1,x2,y2,ans=0;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
ans+=(x2-x1+1)*(y2-y1+1);
if(y1!=y2)ans-=Get(E[0],x1,y1,x2,y2-1);
if(x1!=x2)ans-=Get(E[1],x1,y1,x2-1,y2);
x1--;y1--;ans+=Get(F,x1,y1,x2,y2);
for(int i=x1;i<=x2;i++){
ans-=check(mx[i][y1],my[i][y1],x1,y1,x2,y2);
ans-=check(mx[i][y2],my[i][y2],x1,y1,x2,y2);
}
for(int i=y1;i<=y2;i++){
ans-=check(mx[x1][i],my[x1][i],x1,y1,x2,y2);
ans-=check(mx[x2][i],my[x2][i],x1,y1,x2,y2);
}
printf("%d\n",ans);
for(int i=x1;i<=x2;i++){
v[mx[i][y1]][my[i][y1]]=0;
v[mx[i][y2]][my[i][y2]]=0;
}
for(int i=y1;i<=y2;i++){
v[mx[x1][i]][my[x1][i]]=0;
v[mx[x2][i]][my[x2][i]]=0;
}
}
return 0;
}

P7295-[USACO21JAN]Paint by Letters P【平面图欧拉公式】的更多相关文章

  1. ZOJ 2589 Circles(平面图欧拉公式)

    [题目链接] http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2589 [题目大意] 给出一些圆,问这些圆可以把平面分为几个部 ...

  2. POJ--2284--That Nice Euler Circuit【平面图欧拉公式】

    链接:id=2284">http://poj.org/problem?id=2284 题意:一个自己主动绘图的机器在纸上(无限大)绘图,笔尖从不离开纸,有n个指令,每一个指令是一个坐标 ...

  3. android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索

    我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体 ...

  4. Android ListView A~Z快速索引(改进版)

    上一篇文章虽然实现了ListView 快速索引的效果,但是有一个小小的Bug.这个Bug我在前面也说了,这篇文章就来解决这个Bug. 我研究的时候发现只要showBg值为true,中间的字母就显示,而 ...

  5. 实现ListView A~Z快速索引

    ListView A~Z快速索引这种效果在通信录和城市列表中经常看到,方便用户查找,是一种增加用户体验的好方法. 实现步骤: 1.自定义一个名叫SlideBar 的View. 2.在布局文件中加入这个 ...

  6. Android通讯录管理(获取联系人、通话记录、短信消息)

    前言:前阵子主要是记录了如何对联系人的一些操作,比如搜索,全选.反选和删除等在实际开发中可能需要实现的功能,本篇博客是小巫从一个别人开源的一个项目抽取出来的部分内容,把它给简化出来,可以让需要的朋友清 ...

  7. ZOJ 3781 Paint the Grid Reloaded(BFS)

    题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3781 Leo has a grid with N rows an ...

  8. poj2284 That Nice Euler Circuit(欧拉公式)

    题目链接:poj2284 That Nice Euler Circuit 欧拉公式:如果G是一个阶为n,边数为m且含有r个区域的连通平面图,则有恒等式:n-m+r=2. 欧拉公式的推广: 对于具有k( ...

  9. POJ2284 That Nice Euler Circuit (欧拉公式)(计算几何 线段相交问题)

                                                          That Nice Euler Circuit Time Limit: 3000MS   M ...

随机推荐

  1. 阿里云视频点播获取视频点播的video信息

    背景 因为在项目中需要使用阿里云的视频点播服务,需要获取视频点播的时长信息. 工具类 生成签名串Signature SignatureUtils.java package com.meeno.wzq. ...

  2. 菜鸟的springboot常用注解总结

    菜鸟的springboot常用注解总结 0.前言 可以毫不夸张地说,这篇文章介绍的 Spring/SpringBoot 常用注解基本已经涵盖你工作中遇到的大部分常用的场景.对于每一个注解我都说了具体用 ...

  3. Java第一阶段项目实训

    时间:2016-3-27 17:09 银行综合业务平台业务需求 1.首页  ---------------银行综合业务平台------------------- 1开户     2登录    3.退出 ...

  4. 真实机中安装CentOS

    前言 最近在b站上看了兄弟连老师的Linux教程,非常适合入门:https://www.bilibili.com/video/BV1mW411i7Qf 看完后就自己来试着玩下,正好手上有台空闲的电脑就 ...

  5. Ubuntu 16.04LTS下eclipse连接mysql

    第一部分:打开eclipse,新建一个web工程,新建一个类db_test.java(jdbc连接mysql的原理自行百度) import java.sql.*; public class db_te ...

  6. 利用Python快速绘制海报级别地图

    1 简介 基于Python中诸如matplotlib等功能丰富.自由度极高的绘图库,我们可以完成各种极富艺术感的可视化作品,关于这一点我在系列文章在模仿中精进数据可视化中已经带大家学习过很多案例了. ...

  7. 基于CentOS7.x Linux操作系统,从0开始构建一套Docker虚拟化平台,使用二进制Tar包方式,部署的步骤和方法如下:

    #配置centos7的yum源#建议阿里源#链接:https://yq.aliyun.com/articles/525282?type=2#从Docker官网下载软件包: ls -l docker-1 ...

  8. 浅析Is-a,Has-a与like-a

    在面向对象的设计领域里,有很多设计思路,主要有三种:is-a.has-a.like-a. 这三种在java的类.接口.抽象类中很多体现,下面简述一下其定义. 1.Is-a(继承关系) is-a,顾名思 ...

  9. NOIP模拟22「d·e·f」

    T1:d   枚举.   现在都不敢随便打枚举了.   实际上我们只关注最后留下的矩阵中最小的长与宽即可.   所以我们将所有矩阵按a的降序排列.   从第\(n-m\)个开始枚举.   因为你最多拿 ...

  10. Linux制作根文件系统笔记

    测试平台 宿主机平台:Ubuntu 12.04.4 LTS 目标机:Easy-ARM IMX283 目标机内核:Linux 2.6.35.3 交叉编译器:arm-linux-gcc 4.4.4 Bus ...