HDU 1572 Atlantis 线段树扫描线(矩形面积合并)

HDU 1572 Atlantis

There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.

Input

The input consists of several test cases. Each test case starts with a line containing a single integer n (1 <= n <= 100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0 <= x1 < x2 <= 100000;0 <= y1 < y2 <= 100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.
The input file is terminated by a line containing a single 0. Don't process it.

Output

For each test case, your program should output one section. The first line of each section must be "Test case #k", where k is the number of the test case (starting with 1). The second one must be "Total explored area: a", where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.
Output a blank line after each test case.

Sample Input

2
10 10 20 20
15 15 25 25.5
0

Sample Output

Test case #1
Total explored area: 180.00 

题意:

给定 n 个矩形的对角线坐标,求他们所覆盖的面积(会有重叠)

矩形面积合并

线段树扫描线:(首先将 x端点离散化,方便计算 )将一个矩形拆成两条线(左右边界的横坐标为端点,两个纵坐标定位两条线,上线标记-1,下线标记1),这些线按照 纵坐标y 从小到大排序,然后去按顺序遍历每一条线,更新线段树:线段树记录的是tree.l 到 tree.r区间覆盖了多少次+1-1,将它们叠加到一起,tree,sum 记录这个区间的长度

看图吧,一眼明了
DREAM_yao
DREAM_yao

撸代码:

#include<stdio.h>
#include<math.h>
#include<algorithm>
using namespace std;
struct line
{

    double x1,x2,y,l;
}p[55220];
struct Tree
{

    int l,r,ans;
    double sum;
}tree[51010];

bool comp(line a,line b)
{
    return a.y<b.y;
}
double x[55220];
void build(int l,int r,int root)
{
    tree[root].l=l;
    tree[root].r=r;
    tree[root].ans=0;
    tree[root].sum=0;
    if(l==r)
        return ;
    int mid = (l+r)>>1;
    build(l,mid,root<<1);
    build(mid+1,r,root<<1|1);
    return ;
}

void pushdown(int root)
{
    if(tree[root].ans!=0) tree[root].sum=x[tree[root].r+1]-x[tree[root].l];/**计算长度,而不是点*/
    else if(tree[root].l==tree[root].r) tree[root].sum=0;/**叶子结点,且覆盖0次*/
    else tree[root].sum=tree[root<<1].sum+tree[root<<1|1].sum;/**非叶子结点,ans=0*/
    return ;
}
void update(int l,int r,int kk,int root)
{
    if(l<=tree[root].l&&r>=tree[root].r)
    {
        tree[root].ans+=kk;/**tree.l 到 tree.r区间覆盖了+1或-1*/
        pushdown(root);/**更新sum值*/
        return ;
    }
    int mid=(tree[root].l+tree[root].r)>>1;
    if(l<=mid)update(l,r,kk,root<<1);
    if(mid<r)update(l,r,kk,root<<1|1);
    pushdown(root);
    return ;
}
int main()
{
    int n,t=1;
    while(~scanf("%d",&n)&&n)
    {
        double x1,y1,x2,y2;
        double ans=0;
        int m,k=0;
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            p[k].x1=x1,p[k].x2=x2;
            p[k].y=y1;
            p[k].l=1;
            x[k++]=x1;

            p[k].x1=x1,p[k].x2=x2;
            p[k].y=y2;
            p[k].l=-1;
            x[k++]=x2;
        }
        sort(x,x+k);
        sort(p,p+k,comp);
        m=1;
        for(int i=1;i<k;i++)
        {
            if(x[i]!=x[i-1])
                x[m++]=x[i];
        }
        build(0,m-2,1);/*初始化,m个点 ,就有m-1个线段?*/
        ans=0;
        for(int i=0;i<k-1;i++)
        {
            int l=lower_bound(x,x+m,p[i].x1)-x;
            int r=lower_bound(x,x+m,p[i].x2)-x-1;/**离散化处理,线段而不是点*/
            if(l<=r)/*!!!不用应该也行*/
                update(l,r,p[i].l,1);
            ans+=tree[1].sum*(p[i+1].y-p[i].y);/*所求线的不重合的宽度*/
        }
        printf("Test case #%d Total explored area: %.2f ",t++,ans);

    }
    return 0;
}
原文地址:https://www.cnblogs.com/HappyKnockOnCode/p/12713720.html