Bulletin Board
Problem Description
The ACM Student Chapter has just been given custody of a number of school bulletin boards. Several members agreed to clear off the old posters. They found posters plastered many levels deep. They made a bet about how much area was left clear, what was the greatest depth of posters on top of each other, and how much of the area was covered to this greatest depth. To determine each bet’s winner, they made very accurate measurements of all the poster positions as they removed them. Because of the large number of posters, they now need a program to do the calculations. That is your job.
A simple illustration is shown above: a bulletin board 45 units wide by 40 high, with three posters, one with corners at coordinates (10, 10) and (35, 20), another with corners at (20, 25) and (40, 35), and the last with
corners at (25, 5) and (30, 30). The total area not covered by any poster is 1300. The maximum number of posters on top of each other is 2. The total area covered by exactly 2 posters is 75.
Input
The input will consist of one to twenty data sets, followed by a line containing only 0. On each line the data will consist of blank separated nonnegative integers.
The first line of a dataset contains integers n w h, where n is the number of posters on the bulletin board, w and h are the width and height of the bulletin board. Constraints are 0 < n <= 100; 0 < w <= 50000; 0 < h <= 40000.
The dataset ends with n lines, each describing the location of one poster. Each poster is rectangular and has horizontal and vertical sides. The x and y coordinates are measured from one corner of the bulletin board. Each line contains four numbers xl yl xh and yh, where xl and yl, are the lowest values of the x and y coordinates in one corner of the poster and xh and yh are the highest values in the diagonally opposite corner.Each poster fits on the bulletin board, so 0 2 xl < xh 2 w, and 0 2 yl < yh 2 h.
Output
There is one line of output for each data set containing three integers, the total area of the bulletin board that is not covered by any poster, the maximum depth of posters on top of each other, and the total area covered this maximum number of times.
Caution: An approach examining every pair of integer coordinates might need to deal with 2 billion coordinate pairs.
Sample Input
3 45 40
10 10 35 20
20 25 40 35
25 5 30 30
1 20 30
5 5 15 25
2 2000 1000
0 0 1000 1000
1000 0 2000 1000
3 10 10
0 0 10 10
0 0 10 10
0 0 10 10
0
Sample Output
1300 2 75
400 1 200
0 1 2000000
0 3 100
题意
有一个w*h大的公告板,有n张长方形海报贴在上面,求公告板未被覆盖的面积,海报的最大厚度,厚度等于最大厚度的面积。
题解:
对于求公告板未被覆盖的面积,可以通过扫描线+线段树来求出被覆盖的面积S,然后那总面积-S即可。第二个问题,可以在线段树维护的时候同时维护每个点(区间)被覆盖的次数,求最大的次数即可。第三个问题,可以再维护一个区间中等于最大厚度的长度。扫描线扫描结束,即可求出三个问题的答案。
下面的解法是设扫描线平行于y轴,从0坐标向右扫描。因为本题的所有点都是非负整数,并且数据范围不大,所以x轴并未离散化。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<vector>
#include<queue>
#include<map>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<int, int> P;
const int maxn = 220;
const int mod = 9901;
struct node{
int l, r, x;
node(){}
node(int a, int b, int c):l(a),r(b),x(c){}
};
//p:该段区间被被加的次数,pn:该段区间有线覆盖的长度
int mmx, lz[maxn*4], p[maxn*4], pn[maxn*4];
//mx:该段区间当前最大厚度,mxn:当前区间最大厚度的长度
int len, b[maxn], mx[maxn*4], mxn[4*maxn];
vector<node> g[50100];
int lisan(int num, int a[]);
void creat(int l, int r, int k);
void pushdown(int l, int r, int k);
void pushup(int l, int r, int k);
void Update(int l, int r, int al, int ar, int x, int k);
int main()
{
int n, w, h, i, j, k, num;
while(scanf("%d", &n), n)
{
//初始化
memset(pn, 0, sizeof(pn));
memset(mxn, 0, sizeof(mxn));
memset(p, 0, sizeof(p));
memset(lz, 0, sizeof(lz));
scanf("%d %d", &w, &h);
num = 0;
for(i=0;i<n;i++)
{
int a1, b1, a2, b2;
scanf("%d %d %d %d", &a1, &b1, &a2, &b2);
b[++num] = b1; b[++num] = b2;
g[a1].push_back(node(b1, b2, 1));
g[a2].push_back(node(b1, b2, -1));
}
//离散化y坐标
len = lisan(num+1, b);
b[0] = 0;
creat(1, len, 1);
int mxx = 0, sum1 = 0, sum2 = 0;
//x从0坐标开始,每次扫描1单位长度
for(i=0;i<=w;i++)
{
if(mxx == mx[1])sum2 += mxn[1];
else if(mxx < mx[1]) mxx = mx[1], sum2 = mxn[1];
sum1 += pn[1];
for(j=0;j<g[i].size();j++)
{
int l = lower_bound(b+1, b+1+len, g[i][j].l)-b;
int r = lower_bound(b+1, b+1+len, g[i][j].r)-b;
Update(1, len, l+1, r, g[i][j].x, 1);
}
g[i].clear();
}
printf("%d %d %d\n", (LL)w*h-sum1, mxx, sum2);
}
return 0;
}
int lisan(int num, int a[])
{
sort(a+1, a+1+num);
int len = 0;
a[0] = a[1] - 1;
for(int i=1;i<=num;i++)
if(a[i] != a[len])a[++len] = a[i];
return len;
}
//区间[l,r]代表长度为b[r]-b[l-1]
void creat(int l, int r, int k)
{
p[k] = pn[k] = mx[k] = 0;
mxn[k] = b[r]-b[l-1];
if(l == r) return;
int mid = (l+r)/2;
creat(l, mid, 2*k);
creat(mid+1, r, 2*k+1);
}
void Update(int l, int r, int al, int ar, int x, int k)
{
if(l == al && r == ar)
{
mx[k] += x, lz[k] += x, p[k] += x;
if(l != r)pushdown(l, r, k);
pushup(l, r, k);
return ;
}
pushdown(l, r, k);
int mid = (l+r)/2;
if(ar <= mid)Update(l, mid, al, ar, x, 2*k);
else if(al > mid)Update(mid+1, r, al, ar, x, 2*k+1);
else Update(l, mid, al, mid, x, 2*k),
Update(mid+1, r, mid+1, ar, x, 2*k+1);
pushup(l, r, k);
}
void pushdown(int l, int r, int k)
{
if(lz[k])
{
int mid = (l+r)/2;
lz[2*k] += lz[k];
lz[2*k+1] += lz[k];
mx[2*k] += lz[k];
mx[2*k+1] += lz[k];
lz[k] = 0;
}
}
void pushup(int l, int r, int k)
{
if(p[k])pn[k] = b[r] - b[l-1];
else if(l == r)pn[k] = 0;
else pn[k] = pn[2*k]+pn[2*k+1];
//如果是叶子节点,则长度为b[r]-b[l-1]
if(l == r){
mxn[k] = b[r]-b[l-1];
return;
}
//最大值为其左右儿子中较大的一个
if(mx[2*k] == mx[2*k+1])
mx[k] = mx[2*k], mxn[k] = mxn[2*k]+mxn[2*k+1];
else if(mx[2*k] < mx[2*k+1])
mx[k] = mx[2*k+1], mxn[k] = mxn[2*k+1];
else
mx[k] = mx[2*k], mxn[k] = mxn[2*k];
}