POJ 3277线段树 离线+离散

本文介绍了一种解决多个矩形重叠情况下计算总面积的算法。通过离散化横坐标并使用线段树进行离线处理,该算法能够高效地解决矩形重叠问题。

题意:给定每个矩形的高度以及底边在数轴上的起点和终点。各矩形间可能有重叠。问它们覆盖的总面积是多少。


将横坐标离散化存到线段树中,然后离线算法,从低到高依次更新,后面的直接覆盖前面的即可


#include "stdio.h"
#include "string.h"
#include "math.h"
#include "algorithm"
using namespace std;

struct Mar
{
    __int64 l,r,op;
}mark[40010];

struct B
{
    __int64 l,r;
}b[100010];

struct node
{
    int l,r;
    __int64 zuo,you,cover,x;
}data[400010];

bool cmp(Mar a,Mar b)
{
    return a.op<b.op;
}
void build(int l,int r,int k)
{
    int mid;
    data[k].l=l;
    data[k].r=r;
    data[k].cover=-1;
    data[k].x=0;
    if (l==r)
    {
        data[k].zuo=b[l].l;
        data[k].you=b[l].r;
        return ;
    }
    mid=(data[k].l+data[k].r)/2;
    build(l,mid,k*2);
    build(mid+1,r,k*2+1);

    data[k].zuo=data[k*2].zuo;
    data[k].you=data[k*2+1].you;
}

void Pushdown(int k)
{
    if (data[k].l==data[k].r) return ;
    if (data[k].x==-1) return ;
    data[k*2].x=data[k*2+1].x=data[k].x;
    data[k].x=-1;
}

void updata(__int64 zuo,__int64 you,int k,__int64 op)
{
    if (data[k].x>=op) return ;

    if (data[k].zuo==zuo && data[k].you==you)
    {
        data[k].x=op;
        return ;
    }

    Pushdown(k);

    if (data[k*2].you>=you) updata(zuo,you,k*2,op);
    else
        if (data[k*2+1].zuo<=zuo) updata(zuo,you,k*2+1,op);
    else
    {
        updata(zuo,data[k*2].you,k*2,op);
        updata(data[k*2+1].zuo,you,k*2+1,op);
    }

    if (data[k*2].x==data[k*2+1].x) data[k].x=data[k*2].x;
    else data[k].x=-1;
}
__int64 query(int k)
{
    if (data[k].x!=-1)
    {
        return (data[k].you-data[k].zuo)*data[k].x;
    }

    return query(k*2)+query(k*2+1);
}
int main()
{
    int n,sum,last,m,i;
    __int64 a[100010];
    while (scanf("%d",&n)!=EOF)
    {
        sum=0;
        for (i=1;i<=n;i++)
        {
            scanf("%I64d%I64d%I64d",&mark[i].l,&mark[i].r,&mark[i].op);
            a[sum++]=mark[i].l;
            a[sum++]=mark[i].r;
        }
        sort(a,a+sum);
        last=a[0];
        m=0;
        for (i=1;i<sum;i++)
        {
            if (a[i]!=a[i-1])
            {
                m++;
                b[m].l=last;
                b[m].r=a[i];
                last=a[i];
            }
        }
        sort(mark+1,mark+n+1,cmp);
        build(1,m,1);
        for (i=1;i<=n;i++)
            updata(mark[i].l,mark[i].r,1,mark[i].op);
        printf("%I64d\n",query(1));
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值