SKYLINE UVALive - 4108

我一开始没有想到用线段树,是我学得太僵了...

我们要记录每段的最大高度,而且要组织成区间信息,这要用到线段树

 

怎么用呢?

线段树维护区间最大值;对于每个线段,先二分至其包含区间,如果最大值>=h,就能把这个区间赋值

优化:如果最小值<=h,即可返回

 

这道题算是一个线段树的小魔改吧...

我们发现:对于线段树,查询和修改两个操作是可以合在一起的;找区间也不是固定的,可以根据区间信息,二分至我们目标的区间

#include<iostream>
#include<cstdio>
#include<cstring>

using namespace std;

const int N=1e5+3,V=1e5+3;

struct line{
    int l,r,h;
}a[N];

struct sgt{
    int mn,mx;
    int st;
}R[V<<2];

int gl;
void push_down(int o,int l,int r){
    if(R[o].st)
    {
        R[o<<1].mx=R[o<<1|1].mx=R[o<<1].mn=R[o<<1|1].mn=R[o].st;
        R[o<<1].st=R[o<<1|1].st=R[o].st;
        R[o].st=0;
    }
}
void push_up(int o,int l,int r){
    R[o].mx=max(R[o<<1].mx,R[o<<1|1].mx);
    R[o].mn=min(R[o<<1].mn,R[o<<1|1].mn);
}
int modify(int o,int l,int r)
{
    if(a[gl].l<=l&&a[gl].r>=r)
    {
        if(R[o].mx<=a[gl].h)
        {
            R[o].mx=R[o].mn=a[gl].h;
            R[o].st=a[gl].h;
            return r-l+1;
        }
        else if(R[o].mn>a[gl].h)
            return 0;            
    }
    push_down(o,l,r);
    int mid=(l+r)>>1,ret=0;
    if(a[gl].l<=mid)
        ret+=modify(o<<1,l,mid);
    if(a[gl].r>mid)
        ret+=modify(o<<1|1,mid+1,r);
    push_up(o,l,r);
    return ret;
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n;
        scanf("%d",&n);
        int bd=0;
        for(int i=1;i<=n;i++)
            scanf("%d%d%d",&a[i].l,&a[i].r,&a[i].h),
            a[i].r--,
            bd=max(bd,a[i].r);
        int ans=0;
        memset(R,0,sizeof R);
        for(int i=1;i<=n;i++)
        {
            gl=i;
            ans+=modify(1,1,bd);
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2018-08-12 20:45  mgnfcnt  阅读(109)  评论(0编辑  收藏  举报