hdu 1542 扫描线+线段树

题目大意:求矩形面积的并
思路:按y轴排序,然后将x投影到线段树上做一个线段覆盖问题即可
注意:为了避免重复,线段坐标右端点是开区间,更新时需要加上1

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=2e2+10;
typedef long long ll;
struct Line {
    double x1,x2,h;
    int f;
    bool operator < (const Line &rhs) const {
        return rhs.h>h;
    }
    Line(double x1=0,double x2=0,double h=0,int f=0):x1(x1),x2(x2),h(h),f(f){}
}L[N];
struct Node{
    int l,r,cnt ;double len;
}tr[N<<2];
int n,kase=0; double tmp[N];
void build(int x,int l,int r)
{
    tr[x].l=l;tr[x].r=r;tr[x].len=tr[x].cnt=0;
    if(l==r) {return ;}
    int mid=(l+r)>>1;
    build(x<<1,l,mid);
    build(x<<1|1,mid+1,r);
}
void pushup(int x)
{
    int l=tr[x].l,r=tr[x].r;
    if(tr[x].cnt) 
        tr[x].len=tmp[r+1]-tmp[l];
    else if(l==r) 
        tr[x].len=0;
    else 
        tr[x].len=tr[x<<1].len+tr[x<<1|1].len;
}
void update(int x,int ql,int qr,int delta)
{
    int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;
    if(ql==tr[x].l&&qr==tr[x].r) {
        tr[x].cnt+=delta;
        pushup(x);
        return ;
    }
    if(qr<=mid) update(x<<1,ql,qr,delta);
    else if(ql>mid) update(x<<1|1,ql,qr,delta);
    else {
        update(x<<1,ql,mid,delta);
        update(x<<1|1,mid+1,qr,delta);
    }
    pushup(x);
}
int main()
{
    while(scanf("%d",&n)&&n){
        for(int i=0;i<n;i++) {
            double x1,x2,y1,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            L[i*2]=Line(x1,x2,y1,1);     tmp[i*2]=x1;
            L[i*2+1]=Line(x1,x2,y2,-1);  tmp[i*2+1]=x2;
        }
        sort(L,L+2*n);
        sort(tmp,tmp+2*n);
        int sz=unique(tmp,tmp+2*n)-tmp;
        build(1,0,sz-1);
        double ans=0.0;
        for(int i=0;i<n*2-1;i++) {
            int l=lower_bound(tmp,tmp+sz,L[i].x1)-tmp;
            int r=lower_bound(tmp,tmp+sz,L[i].x2)-tmp-1;
            update(1,l,r,L[i].f);
            ans+=(tr[1].len*(L[i+1].h-L[i].h));
        }
        printf("Test case #%d\nTotal explored area: %.2lf\n\n",++kase,ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值