HDU - 1255 覆盖的面积 面积交

本文深入解析HDU-1255覆盖面积问题,介绍了一种基于区间并集算法的解决方案,通过构建线段树来高效计算线段覆盖的总长度及两次以上覆盖的长度,适用于解决计算机科学中复杂的区间覆盖问题。

HDU - 1255 覆盖的面积

这道题在区间并的基础上稍微修改了一下,多了一个记录覆盖两次或两次以上的长度变量 ss 和 判断条件

详细讲解  Titanium

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ls rt<<1
#define rs rt<<1|1
#define mid(rt) (p[rt].l+p[rt].r)>>1
using namespace std;
const int maxn=10010;
struct edge
{
    double l,r,h;
    int v;
}e[maxn<<2];

bool cmp(edge a,edge b)
{
    return a.h<b.h;
}

double x[maxn<<2];

struct node
{
    int l,r;
    int cnt;     //该节点被覆盖的情况
    double s;    //覆盖一次的长度
    double ss;   //覆盖两次或两次以上的长度
}p[maxn<<2];

void build(int l,int r,int rt)
{
    p[rt].cnt = 0;
    p[rt].s = p[rt].ss = 0;
    p[rt].l = l , p[rt].r = r;
    if(l==r)
        return ;
    int m = mid(rt);
    build(l,m,ls);
    build(m+1,r,rs);
}

void pushup(int rt)
{ 
    if(p[rt].cnt)         //非零,已经被整段覆盖
        p[rt].s = x[p[rt].r+1]-x[p[rt].l];       //利用[ , ),这个区间性质,左闭右开
    else if(p[rt].l==p[rt].r)       //这是一个点而不是线段
        p[rt].s = 0;
    else                         //是一条没有整个区间被覆盖的线段,合并左右子的信息
        p[rt].s = p[ls].s + p[rs].s;

    if(p[rt].cnt>1)      //区间被覆盖2次或2次以上
        p[rt].ss = x[p[rt].r+1]-x[p[rt].l];
    else if(p[rt].l==p[rt].r)    //叶子结点
        p[rt].ss = 0;
    else if(p[rt].cnt==1)       //被完全覆盖1次(不确定有无覆盖两次或两次以上的部分)
        p[rt].ss = p[ls].s+p[rs].s;
    else                     //不完全不知道被覆盖的情况(不知道有没有被覆盖,被覆盖了几次,长度是多少都不知道)
        p[rt].ss = p[ls].ss+p[rs].ss;
}

void update(int l,int r,int rt,int f)
{
    if(p[rt].l==l && p[rt].r==r)
    {
        p[rt].cnt += f;
        pushup(rt);
        return ;
    }
    int m = mid(rt);
    if(r<=m)
        update(l,r,ls,f);
    else if(l>m)
        update(l,r,rs,f);
    else
    {
        update(l,m,ls,f);
        update(m+1,r,rs,f);
    }
    pushup(rt);
} 

int main()
{
    int t,n;
    double x1,y1,x2,y2;
    scanf("%d",&t);
    while(t--)
    {
        int tot=0;
        scanf("%d",&n);
        for(int i=0;i<n;i++)
        {
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            e[tot].l = e[tot+1].l = x[tot] = x1;
            e[tot].r = e[tot+1].r = x[tot+1] = x2;
            e[tot].h = y1;
            e[tot+1].h = y2;
            e[tot].v = 1;
            e[tot+1].v = -1;
            tot += 2;
        }
        sort(e,e+tot,cmp);
        sort(x,x+tot);
        int k = unique(x,x+tot)-x;
        build(0,k-1,1);
        double ans=0;
        for(int i=0;i<tot;i++)
        {
            int l=lower_bound(x,x+k,e[i].l)-x;
            int r=lower_bound(x,x+k,e[i].r)-x-1;
            update(l,r,1,e[i].v);
            ans += (e[i+1].h-e[i].h)*p[1].ss;
        }
        printf("%.2lf\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值