UVALive 4108 SKYLINE

       这题写了三四天,真是写郁闷了,后来才发现自己这题写2B了,唉,桑心。

题意:在地平线上依次建n座建筑物。建筑物的修建按照从后往前的顺序,修建完一座建筑物以后,统计它在多长的部分是最高的,并把这个长度称为“覆盖度”,最后输出总的覆盖度。

思路:刚开始的时候,我的思路比较简单,就是记录每个区间最高的建筑物有多高,如果要修建的这个建筑物的高度比这个区间最高的建筑物还高,那么这个结果就要加上这个区间的长度,否则就接着找下去。但是这样的话会有问题,将一个区间分为两部分的时候,分开的那部分很难计算,比如区间[1,6]分为两个区间[1,3]、[4,6],那么[3,4]这个区间的值就不好计算了,当时写的时候加了好多特判,搞得乱七八糟的,还是各种wrong。其实这个问题换个角度看会容易很多:对于每个单位区间,比如[3,3],我们记录的值可以看做从3到4之前的这个区间中建筑物的最大值,这样的话,每次更新的时候更新的就是l~r-1的这段区间,查询按上面的方法去搞就行了,当这个区间最高的建筑物比要修建的建筑物低,那么直接在sum中加上区间的长度r-l+1即可。

 

代码:

 

#include <iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
//typedef long long ll;
const int maxn=100000+10;
const int N=100000;
int hightv[maxn<<2],setv[maxn<<2];
bool flag[maxn<<2];
int sum;
void PushUp(int rt)
{
    int ls=rt<<1,rs=rt<<1|1;
    hightv[rt]=max(hightv[ls],hightv[rs]);
    flag[rt]=(hightv[ls]==hightv[rs])&&flag[ls]&&flag[rs];
}
void PushDown(int rt)
{
    if(setv[rt]>=0)
    {
        int ls=rt<<1,rs=rt<<1|1;
        if(setv[rt]>=hightv[ls])
        {
            hightv[ls]=setv[rt];
            flag[ls]=true;
        }
        if(setv[rt]>=hightv[rs])
        {
            hightv[rs]=setv[rt];
            flag[rs]=true;
        }
        setv[ls]=max(setv[ls],setv[rt]);
        setv[rs]=max(setv[rs],setv[rt]);
        setv[rt]=-1;
    }
}
void build(int l,int r,int rt)
{
    hightv[rt]=0;
    setv[rt]=-1;
    flag[rt]=true;
    if(l==r) return;
    int m=(l+r)>>1;
    build(l,m,rt<<1);
    build(m+1,r,rt<<1|1);
}
void Update(int v,int L,int R,int l,int r,int rt)
{
    if(l>=L&&r<=R&&hightv[rt]<=v)
    {
        sum+=(r-l+1);
        setv[rt]=hightv[rt]=v;
        flag[rt]=true;
        return;
    }
    if(l>=L&&r<=R&&hightv[rt]>v&&flag[rt])
    {
        return;
    }
    PushDown(rt);
    int m=(l+r)>>1;
    int ls=rt<<1,rs=rt<<1|1;
    if(m>=L)
      Update(v,L,R,l,m,ls);
    if(m<R)
      Update(v,L,R,m+1,r,rs);
    PushUp(rt);
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,l,r,h;
    int t;
    while(cin>>t)
    {
        if(t==0) break;
        while(t--)
        {
            cin>>n;
            build(1,N,1);
            int res=0;
            for(int i=0;i<n;++i)
            {
                cin>>l>>r>>h;
                sum=0;
                Update(h,l,r-1,1,N,1);
                res+=sum;
            }
            cout<<res<<endl;
        }
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值