[USACO3.1]形成的区域(P6432)

日期:2020-05-31

一、题意分析

题目链接

  1. 任务:给出一张宽为\(A\)长为\(B\)的白纸(颜色为\(1\)),现要求将\(N\)个有颜色且不透明的长方形顺序放在白纸上,可能重叠。求放好后那张纸上呈现的每种颜色的面积。
  2. 输入:第一行三个正整数\(A \ B \ N\),分别表示白纸的长、白纸的宽、长方形的个数;第\(2\)到\(N+1\)行,每行五个整数\(llx \ lly \ urx \ ury \ color\),表示有一个左下角坐标为\((llx,lly)\)、右上角坐标为\((urx,ury)\)、颜色为\(color\)的长方形。
  3. 输出:放好长方形后,输出且只输出那张纸上可视颜色的汇总。每行输出两个正整数,该可视颜色和其总可视面积。输出时按照\(color\)升序输出。
  4. 数据范围(原题):\(1 \leq N \leq 10^3\),\(1 \leq A, B \leq 10^4\),\(1 \leq color \leq 2.5 \times 10^3\)。

二、算法分析

1. 暴力

我们知道,暴力的时间复杂度为\(O(A·B·N)\),即\(10^{11}\),故无法\(AC\)。

所以,我们在\(Excel\)上枚举暴力的过程,看看能否有所发现。

输入样例

20 20 3

2 2 18 18 2

0 8 19 19 3

8 0 10 19 4

0). 初始状态(红点为原点)

1). 放第一个长方形

2). 放第二个长方形

3). 放第三个长方形

4). 验证(用\(COUNTIF\)函数)

1 91
2 84
3 187
4 38

画图后,我们发现:其实填了大片相同的数字(颜色),如果我们只用一个数字来表示这个区域(小长方形)的话,那就会快很多。

2. 离散化

1). 扫描线

根据上面的想法,我们来绘制这三个长方形和黑色边框的白纸的扫描线。扫描线就是长方形的四边所在的直线(重叠的只画一条,因为有且只有一条):

那么,扫描线将这张白纸分为若干个长方形。我们只需要在处理每个长方形时,对涉及到的小长方形填上一个数字(代表一种颜色)即可,而非将每一个面积为\(1\)的最小单位填色。

2). 实现

初始化

扫描完毕后,将这张纸被切割成的每个小长方形填上\(1\),表示现在是一张白纸:

放第一个长方形

将第一个长方形涉及到的小长方形填上一个数字:

放第二个长方形

将第二个长方形涉及到的小长方形填上一个数字:

放第三个长方形

将第三个长方形涉及到的小长方形填上一个数字:

统计

一个可视颜色的总面积,就相当于所有和其颜色(数字)相等的被分割的小长方形的面积和。

三、程序框架

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std; const int N = 1100;
const int N2 = 2200;
const int C = 2750;
const int AB = 11000; struct node{
int llx, lly, urx, ury, color;
};
node data[N]; //data存储每个长方形的信息
int map[N2][N2]; //map存储被分割(扫描)后的纸
//linex和liney存储扫描线
//rflcx和rflcy存储映射,即长方形的原始线对应的扫描线编号
//ans[i]表示第i号颜色的总可视面积
int linex[N2], liney[N2], rflcx[AB], rflcy[AB], ans[C];
int a, b, n, numx, numy, maxc; int main(){
//读入
scanf("%d%d%d", &a, &b, &n); //读入长方形 然后做扫描线
numx = numy = 0; maxc = 1;
for (int i = 1; i <= n; ++i) {
scanf("%d%d%d%d%d", &data[i].llx, &data[i].lly, &data[i].urx, &data[i].ury,&data[i].color); linex[++numx] = data[i].llx;
linex[++numx] = data[i].urx;
liney[++numy] = data[i].lly;
liney[++numy] = data[i].ury; if (maxc < data[i].color) maxc = data[i].color; //求最大颜色编号
} //处理边界(白纸的)扫描线
linex[++numx] = 0;
linex[++numx] = a;
liney[++numy] = 0;
liney[++numy] = b; //排序
sort(linex + 1, linex + numx + 1);
sort(liney + 1, liney + numy + 1); //去重
int tmp = numx; numx = 1;
for(int i = 2; i <= tmp; ++i)
if (linex[i] != linex[numx]) linex[++numx] = linex[i]; tmp = numy; numy = 1;
for(int i = 2; i <= tmp; ++i)
if (liney[i] != liney[numy]) liney[++numy] = liney[i]; //做映射
for (int i = 1; i <= numx; ++i) rflcx[linex[i]] = i;
for (int i = 1; i <= numy; ++i) rflcy[liney[i]] = i; //初始化:全部赋值为1,表示白纸
for (int i = 1; i < numx; ++i)
for (int j = 1; j < numy; ++j) map[i][j] = 1; //用长方形不断进行填色
for (int k = 1; k <= n; ++k)
for (int i = rflcx[data[k].llx]; i < rflcx[data[k].urx]; ++i)
for (int j = rflcy[data[k].lly]; j < rflcy[data[k].ury]; ++j) map[i][j] = data[k].color; //统计可视颜色面积
memset(ans, 0, sizeof ans);
for (int i = 1; i < numx; ++i)
for (int j = 1; j < numy; ++j) ans[map[i][j]] += (linex[i + 1] - linex[i]) * (liney[j + 1] - liney[j]); //输出答案
for (int i = 1; i <= maxc; ++i)
if (ans[i] > 0) printf("%d %d\n", i, ans[i]); return 0;
}

[USACO3.1]形成的区域(扫描线+离散化)的更多相关文章

  1. HDU - 1255 覆盖的面积(线段树求矩形面积交 扫描线+离散化)

    链接:线段树求矩形面积并 扫描线+离散化 1.给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. 2.看完线段树求矩形面积并 的方法后,再看这题,求的是矩形面积交,类同. 求面积时,用被覆 ...

  2. hdu1542 Atlantis (线段树+扫描线+离散化)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

  3. POJ-1151-Atlantis(线段树+扫描线+离散化)[矩形面积并]

    题意:求矩形面积并 分析:使用线段树+扫描线...因为坐标是浮点数的,因此还需要离散化! 把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用col表示该区间有多少个下边,sum代表该区 ...

  4. poj1151 Atlantis (线段树+扫描线+离散化)

    有点难,扫描线易懂,离散化然后线段树处理有点不太好理解. 因为这里是一个区间,所有在线段树中更新时,必须是一个长度大于1的区间才是有效的,比如[l,l]这是一根线段,而不是区间了. AC代码 #inc ...

  5. Helter Skelter (扫描线 + 离散化 + 树状数组)

    扫描线:按照其中一个区间的标记为pos,然后左区间标记d为正影响,有区间标记d为负影响,然后根据所有的pos排序.pos从小扫到大,那么对于某一个区间一定会被扫过2次,那么经过2次之后就只剩下中间那一 ...

  6. HDU1542 扫描线+离散化

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Su ...

  7. hdu 4419 线段树 扫描线 离散化 矩形面积

    //离散化 + 扫描线 + 线段树 //这个线段树跟平常不太一样的地方在于记录了区间两个信息,len[i]表示颜色为i的被覆盖的长度为len[i], num[i]表示颜色i 『完全』覆盖了该区间几层. ...

  8. HDU1255 覆盖的面积 —— 求矩形交面积 线段树 + 扫描线 + 离散化

    题目链接:https://vjudge.net/problem/HDU-1255 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input输入数据的第一行是一个正整数T(1<= ...

  9. HDU 1542 Atlantis (线段树 + 扫描线 + 离散化)

    Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total S ...

随机推荐

  1. (十一)Maven之profile实现多环境配置动态切换

    原文链接:https://www.cnblogs.com/zeng1994/p/a442108012ffd6a97b22c63055b48fe9.html 一.多环境配置文件的放置  将不同环境下的配 ...

  2. log报错的原因解决

    idea未装lombok的插件: 1.用快捷键Ctrl+Alt+S打开:Settings→Plugins→Browse repositories 2.输入lom后选择Install,安装插件 3.按照 ...

  3. 怎样在LaTeX中使用中文

    因为疫情在家中上课,作业提交都必须使用PDF.反正时间充裕,不如趁机回顾一下LaTeX的使用. 之前一直用的是Vimtex,但是感觉还是不太方便,于是改用了Texpad.Texpad的强大之处在于它支 ...

  4. android中的逐帧动画

    在android中实现动画最简单的一种方式就是使用逐帧动画(AnimationDrawable).逐帧动画的原理同最古老的动画机制是一样的,通过快速的播放一组变化微小的图片,在人眼的视差时间下,达到一 ...

  5. idea创建项目

    选项详解如下: Create New Project:创建一个新的工程.Import Project:导入一个现有的工程.Open:打开一个已有工程.比如:可以打开 Eclipse 项目.Check ...

  6. 事务的特性ACID、隔离级别

    1.事务特性ACID 1.1 事务的四大特性 1.原子性(Atomicity) 事务包装的一组sql,要么都执行成功,要么都失败.这些操作是不可分割的. 2.一致性(Consistency) 数据库的 ...

  7. ODBC 常见数据源配置整理

    目录 1. 简介 1.1 ODBC和JDBC 1.2 ODBC配置工具 1.3 ODBC 数据源连接配置 2. MySQL 数据源配置 2.1 配置步骤 2.2 链接参数配置 3. SQLServer ...

  8. 面试题64:求 1 + 2 + ... + n

    这道题目条件限制严格,需要发散思维...但是作者是以 C++ 语言特性来做讲解的,对于 Java 狗只能说稍微有点参考意义吧!

  9. java scoket Blocking 阻塞IO socket通信四

    记住NIO在jdk1.7版本之前是同步非阻塞的,以前的inputsream是同步阻塞的,上面学习完成了Buffer现在我们来学习channel channel书双向的,以前阻塞的io的inputstr ...

  10. jfinal运行时报错分析java.lang.ClassNotFoundException: com.sun.faces.config.ConfigureListener

    这里解释一下,我用maven jetty运行没啥问题的项目,当我切换tomcat时候出现如下错误. 问题1. - jar not loaded. See Servlet Spec 3.0, secti ...