hdu_2704 Bulletin Board(扫描线+线段树)

Bulletin Board

Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 32768/32768 K (Java/Others)
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];
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值