【USACO 3.1.4】形成的区域

时间:2022-04-14 20:51:33

【描述】

          N个不同的颜色的不透明的长方形(1 <= N <= 1000)被放置在一张宽为A长为B的白纸上。
这些长方形被放置时,保证了它们的边于白纸的边缘平行。
所有的长方形都放置在白纸内,所以我们会看到不同形状的各种颜色。(颜色用[1,1000]内的整数表示)
坐标系统的原点(0,0)设在这张白纸的左下角,而坐标轴则平行于边缘。
 

【格式】

PROGRAM NAME: rect1
INPUT FORMAT:(file rect1.in)
 
每行输入的是放置长方形的方法。
第一行输入的是那个放在底的长方形(即白纸)。
第 1 行: A , B 和 N, 由空格分开 (1 <=A, B<=10,000)
第 2 到N+1行: 为五个整数 llx, lly, urx, ury, color 这是一个长方形的左下角坐标,右上角坐标和颜色。
颜色 1和底部白纸的颜色相同。
OUTPUT FORMAT:(file rect1.out)

输出文件应该包含一个所有能被看到颜色连同该颜色的总面积的清单( 即使颜色的区域不是连续的),按color的增序顺序。
不要显示没有区域的颜色。

【分析】

本来想用离散化的,结果发现会超时...

借鉴了一个很好的思想,漂浮法。

漂浮法:以逆序来进行放置,即n to 1。逆序的好处在于放置一个矩形后,俯视看到的就是最终俯视该矩形应该看到的。因为挡着它的矩形在之前已经放置好了,所以可直接统计,为递归创造了条件。每放一个矩形,可以想象成将其扔入一密度很大的海水底部,海分成了n层,然后矩形开始向上浮。在上浮过程中若碰撞到其他的矩形则断裂成几个小矩形,继续上浮,直到浮出水面。用递归来模拟上浮过程。

 #include <cstdlib>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
const int maxn=+;
using namespace std;
int lx[maxn],ly[maxn],rx[maxn],ry[maxn];
int color[maxn]={},S[],N;
//前四个为矩形的坐标颜色
void cover(int x1,int y1,int x2,int y2,int c,int h)
{
if (x1==x2 || y1==y2) return;//去掉面积为0的矩阵
if (h>N) S[c]+=(y2-y1)*(x2-x1);
else
{
//断裂成四个小矩形
if (y1<ly[h]) cover(min(rx[h],x1),y1,min(rx[h],x2),min(ly[h],y2),c,h+);
if (x2>rx[h]) cover(max(rx[h],x1),min(ry[h],y1),x2,min(ry[h],y2),c,h+);
if (y2>ry[h]) cover(max(lx[h],x1),max(ry[h],y1),max(lx[h],x2),y2,c,h+);
if (x1<lx[h]) cover(x1,max(ly[h],y1),min(lx[h],x2),max(ly[h],y2),c,h+);
}
}
int main()
{
int i;
//文件操作
freopen("rect1.in","r",stdin);
freopen("rect1.out","w",stdout); scanf("%d%d%d",&rx[],&ry[],&N);//白纸
for (i=;i<=N;i++) scanf("%d%d%d%d%d",&lx[i],&ly[i],&rx[i],&ry[i],&color[i]); S[color[N]]+=(rx[N]-lx[N])*(ry[N]-ly[N]);//最后一张纸 for (i=N-;i>=;i--) cover(lx[i],ly[i],rx[i],ry[i],color[i],i+);
for (i=;i<=maxn;i++) if (S[i]!=) printf("%d %d\n",i,S[i]);
return ;
}