City Horizon poj3277 线段树+离散化

   这道题做得真心不容易,首先是离散化纠结了许久,然后就是线段树竟然还会写得有漏洞敲打,最后就是数据范围了,这题的数据超强的啊,最后结果要用__int64,但我还是忽略了中间计算过程也会超范围,最后各种无语。。。

然后说下这题的思路吧,由于坐标的变化范围很大,而城市最多只有40000个(其实是400000个,奉献了几个re),所以很容易想到用离散化。离散化后接下来就是插入线段了,计算面积时当然就要知道这段的最大高度了。但此处有个小技巧,如果我们按照数据给定的顺序插的话,在插入的过程中我们就需要加判断,这样难免显得会很麻烦,因此我们可以对数据按照高度从小到大进行排序,再按这个顺序插入线段。奋斗

#include <iostream>
#include<algorithm>
#include<cstdio>

using namespace std;
const int maxn=40100;
struct house
{
    int l,r,h;
    bool operator<(const struct house t)const
    {
        return h<t.h;
    }
}h[maxn];//离散化后的

struct pp
{
    int id,key;
    bool isLeft;
    bool operator<(const struct pp t)const
    {
        return key<t.key;
    }
}q[maxn*2];//离散化前的

struct node
{
    __int64 l,r,h;
}p[maxn*4];

int index[maxn];//映射数组

void build_tree(int l,int r,int rt)
{
    p[rt].l=l;
    p[rt].r=r;
    p[rt].h=0;
    if(l==r-1)
        return;
    int mid=(l+r)>>1;
    build_tree(l,mid,rt<<1);
    build_tree(mid,r,rt<<1|1);
}

void init(int n)
{
    int i,j,k;
    for(i=1,j=1;i<=n;i++)
    {
        scanf("%d",&q[j].key);
        q[j].isLeft=true;
        q[j].id=i;
        j++;
        scanf("%d",&q[j].key);
        q[j].isLeft=false;
        q[j].id=i;
        j++;
        scanf("%d",&h[i].h);
    }
    sort(q+1,q+j);
    for(i=1,k=0;i<j;i++)
    {
        if(q[i].key!=q[i-1].key)
            index[++k]=q[i].key;
        if(q[i].isLeft)
            h[q[i].id].l=k;
        else
            h[q[i].id].r=k;
    }
    sort(h+1,h+n+1);//对离散后的数据按高度排序
    build_tree(1,k,1);
}

__int64 query(int rt)
{
    if(p[rt].h)
        return p[rt].h*(index[p[rt].r]-index[p[rt].l]);//此处计算可能超范围
    else if(p[rt].l==p[rt].r-1)
        return 0;
    return query(rt<<1)+query(rt<<1|1);
}

void insert(int l,int r,int d,int rt)
{
    if(p[rt].l==l&&p[rt].r==r)
    {
        p[rt].h=d;
        return;
    }
    if(p[rt].h)//下传
    {
        p[rt<<1].h=p[rt<<1|1].h=p[rt].h;
        p[rt].h=0;
    }
    int mid=(p[rt].l+p[rt].r)>>1;
    if(r<=mid)
        insert(l,r,d,rt<<1);
    else if(l>=mid)
        insert(l,r,d,rt<<1|1);
    else
    {
        insert(l,mid,d,rt<<1);
        insert(mid,r,d,rt<<1|1);
    }
}


int main()
{
    int n;
    scanf("%d",&n);
    init(n);
    for(int i=1;i<=n;i++)
        insert(h[i].l,h[i].r,h[i].h,1);
    printf("%I64d\n",query(1));
    return 0;
}
/*
5
1 5 10
2 6 30
3 7 20
4 6 15
5 10 5
*/


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值