hdu1542 Atlantis (线段树扫描线,矩形覆盖面积并)

问题描述

有几个古希腊文本包含了对传说中的亚特兰蒂斯岛的描述。其中一些文本甚至包括该岛部分地区的地图。但不幸的是,这些地图描述了亚特兰蒂斯的不同区域。你的朋友比尔必须知道地图存在的总面积。你(不明智地)自愿编写一个程序来计算这个数量。

输入

输入文件由几个测试用例组成。每个测试用例都以一行开始,其中包含一个可用映射的整数n (1<=n<=100)。下面的n行描述了每个映射。每一行包含四个数字x1、y1、x2、y2 (0<=x1<x2<=100000;0<=y1<y2<=100000),不一定是整数。的值(x1;y1)和(x2;y2)是左上角resp的坐标。地图区域的右下角。
输入文件被包含一个0的行终止。不处理它。

输出

对于每个测试用例,程序应该输出一个部分。每个部分的第一行必须测试案例# k, k是测试用例的数量(从1开始)。第二个必须“探索总面积:”,其中一个是总开发面积(即联盟的矩形的面积在本测试用例),印刷精确到小数点右边的两个数字。
在每个测试用例之后输出一个空行。

Sample Input

2
10 10 20 20
15 15 25 25.5
0

Sample Output

Test case #1
Total explored area: 180.00

分析:

个人觉得思路写的很清楚(不过代码就… ):konjak魔芋的博客

之前一直拖着没学扫描线,补一下。

因为数组下标不能是double所以用离散化搞成int
线段树维护底部扫描线长度和,乘上两条扫描线之间的距离差,累加至答案就行了

code:
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
typedef long long ll;
const int inf=0x3f3f3f3f;
const int inn=0x80808080;
using namespace std;
const int maxm=205;
struct Line{
    double l,r,h;
    int f;
    Line(){};
    Line(double ll,double rr,double hh,int ff){
        l=ll,r=rr,h=hh,f=ff;
    }
}e[maxm<<2];
bool cmp(Line a,Line b){
    return a.h<b.h;
}
struct Node{
    int cnt;//表示覆盖了几次
    double len;//长度
}a[maxm<<2];
double x[maxm<<2];
void pushup(int l,int r,int node){
    if(a[node].cnt){//不为0说明全覆盖
        a[node].len=x[r+1]-x[l];//用x数组更新长度
    }else if(l==r){//如果是点就没有长度
        a[node].len=0;
    }else{//子节点长度和
        a[node].len=a[node*2].len+a[node*2+1].len;
    }
}
void update(int st,int ed,int l,int r,int node,int val){
    if(st<=l&&ed>=r){
        a[node].cnt+=val;
        pushup(l,r,node);
        return ;
    }
    int mid=(l+r)/2;
    if(st<=mid){
        update(st,ed,l,mid,node*2,val);
    }
    if(ed>=mid+1){
        update(st,ed,mid+1,r,node*2+1,val);
    }
    pushup(l,r,node);
}
int main(){
    int n;
    int cas=1;
    while(cin>>n&&n){
        int cnt=0;
        for(int i=0;i<n;i++){
            double x1,y1,x2,y2;
            cin>>x1>>y1>>x2>>y2;
            x[cnt]=x1;
            e[cnt++]=Line(x1,x2,y1,1);//下面的线
            x[cnt]=x2;
            e[cnt++]=Line(x1,x2,y2,-1);//上面的线
        }
        sort(x,x+cnt);
        sort(e,e+cnt,cmp);
        int m=unique(x,x+cnt)-x;
        double ans=0;
//        memset(a,0,sizeof a);//初始化树(因为树很小所以就不写build函数了)
//        如果下一行的循环条件是i<cnt-1就要用memset初始化一下
//        如果是i<cnt,最后一次update的时候会把所有都清零
        for(int i=0;i<cnt;i++){
            int l=lower_bound(x,x+m,e[i].l)-x;
            int r=lower_bound(x,x+m,e[i].r)-x-1;//区间左闭右开,所以减1
            update(l,r,0,m-1,1,e[i].f);
            ans+=a[1].len*(e[i+1].h-e[i].h);
        }
        printf("Test case #%d\n",cas++);
        printf("Total explored area: %.2f\n\n",ans);//不知道为啥自己电脑用lf会输出0但是提交能过,用f就没事
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值