矩形面积并集,2017ICPC网络赛(南宁)Overlapping Rectangles

【矩形的面积之并集】

推荐博客:http://www.cnblogs.com/kane0526/archive/2013/02/26/2934214.html

【题意】:

在坐标系中,第一象限有一些矩形(不在第一象限时,平移过去),给出矩形顶点的坐标。

最后问这些矩形的覆盖区域的面积,重叠部分只算一次。

【解题思路】:

先看图(来自上文博客)


如图,两个矩形相交时,每个横边延伸开,将两个矩形分成三部分,绿、蓝、紫。

这两个矩形的面积并集就是这三个区域的面积和。

当有n个矩形时,从最矮的横线开始往上爬,把每一层的面积统计起来,最后加和就是面积并集。


如果这里明白了的话,下面的实现完全可以自己思考了。

横边直接按y坐标扫描,竖边用线段树维护,或者直接一维数组暴力维护(不超时的情况下)

横边的左右端点看做区间!

【解题步骤】

1、把所有矩形的横边拆下来,排序,以便扫描,从下往上爬。

这里有一个技巧,把矩形的上边标记为-1,下边标记为1;

原因是方便记录区间的标记与否。遇到1时把区间加一层标记,遇到-1时减一层标记。

2、至于每一层覆盖了多少,其实就是被标记的区间之和。

3、这一层的高度,乘上这一层覆盖区间的长度,即为这一层的面积

【优化】:

区间的维护,可以将区间离散化,比如出现小数时,只能离散化。

方法是把所有用到的端点,排序,做小到大编号,用编号来代表那个数,很明了。


【例题】:

计蒜客(2017南宁网络赛的一个题,矩形面积并集)

There are nn rectangles on the plane. The problem is to find the area of the union of these rectangles. Note that these rectangles might overlap with each other, and the overlapped areas of these rectangles shall not be counted more than once. For example, given a rectangle AA with the bottom left corner located at (0, 0)(0,0)and the top right corner at (2, 2)(2,2), and the other rectangle BB with the bottom left corner located at (1,1)(1,1) and the top right corner at (3,3)(3,3), it follows that the area of the union of AA and BBshould be 77, instead of 88.

Although the problem looks simple at the first glance, it might take a while to figure out how to do it correctly. Note that the shape of the union can be very complicated, and the intersected areas can be overlapped by more than two rectangles.

Note:

(1) The coordinates of these rectangles are given in integers. So you do not have to worry about the floating point round-off errors. However, these integers can be as large as 1,000,0001,000,000.

(2) To make the problem easier, you do not have to worry about the sum of the areas exceeding the long integer precision. That is, you can assume that the total area does not result in integer overflow.

Input Format

Several sets of rectangles configurations. The inputs are a list of integers. Within each set, the first integer (in a single line) represents the number of rectangles, n, which can be as large as 10001000. After n, there will be n lines representing the n rectangles; each line contains four integers <a, b, c, d><a,b,c,d> , which means that the bottom left corner of the rectangle is located at (a, b)(a,b), and the top right corner of the rectangle is located at (c, d)(c,d). Note that integers aabbccdd can be as large as 1,000,0001,000,000.

These configurations of rectangles occur repetitively in the input as the pattern described above. An integer n = 0n=0 (zero) signifies the end of input.

Output Format

For each set of the rectangles configurations appeared in the input, calculate the total area of the union of the rectangles. Again, these rectangles might overlap each other, and the intersecting areas of these rectangles can only be counted once. Output a single star '*' to signify the end of outputs.

样例输入
2
0 0 2 2
1 1 3 3
3
0 0 1 1
2 2 3 3
4 4 5 5
0
样例输出
7
3
*
题目来源

2017 ACM-ICPC 亚洲区(南宁赛区)网络赛

【线段树代码】:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+5;
int t[N*2];//标记数量
int vis[N+2];//标记数组
void update(int root,int kl,int kr,int num,int l=1,int r=N)//区间修改[kl,kr]
{
    if(l==r){
        vis[l]+=num;
        if(vis[l]==0)t[root]=0;
        else t[root]=1;
        return;
    }
    int mid=(l+r)/2;
    if(kl<=mid)
        update(root*2,kl,kr,num,l,mid);
    if(kr>mid)
        update(root*2+1,kl,kr,num,mid+1,r);
    t[root]=t[root*2]+t[root*2+1];
}
struct node{//存边
    int l,r,y,flag;//横边,高度,朝向
}p[2200];
bool cmp(node a,node b){
    return a.y<b.y;
}
int main()
{
    int n,a,b,c,d;
    while(scanf("%d",&n),n)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            p[i]=node{a,c,b,1};
            p[i+n]=node{a,c,d,-1};//上边
        }
        sort(p+1,p+2*n+1,cmp);
        memset(vis,0,sizeof(vis));
        ll ans=0;
        for(int i=1;i<=2*n;i++)
        {
            ans+=(ll)(p[i].y-p[i-1].y)*t[1];
            update(1,p[i].l+1,p[i].r,p[i].flag);
        }
        printf("%lld\n",ans);
    }
    puts("*");
}
【暴力维护的代码】:(奇怪的是提交运行时间比线段树要快很多,,,,,)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node{//存边
    int l,r,y,flag;//横边,高度,朝向
}p[2200];
int dp[2200];
int M[2200];
bool cmp(node a,node b){
    return a.y<b.y;
}
int main()
{
    int n,a,b,c,d;
    while(scanf("%d",&n),n)
    {
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d%d",&a,&b,&c,&d);
            M[i]=a;
            M[i+n]=c;
            p[i]=node{a,c,b,1};
            p[i+n]=node{a,c,d,-1};//上边
        }
        sort(M+1,M+2*n+1);
        sort(p+1,p+2*n+1,cmp);
        memset(dp,0,sizeof(dp));
        ll ans=0;
        for(int i=1;i<=2*n;i++)
        {
            ll sum=0;
            for(int  j=1;j<=2*n;j++)if(dp[j])sum+=M[j]-M[j-1];
            ans+=(p[i].y-p[i-1].y)*sum;
            for(int j=1;j<=2*n;j++)
                if(M[j]==p[i].l){
                    j++;
                    while(j<=2*n&&M[j]<=p[i].r)dp[j++]+=p[i].flag;
                    break;
                }
        }
        printf("%lld\n",ans);
    }
    puts("*");
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪的期许

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值