P2003 [CRCI2007-2008] PLATFORME 平板(线段树)

题目传送门

平板

题目大意

一个空间中,给你n个板子,分别告知你每个板子的高度和水平的边缘坐标
上面的板子可以搭建在下面的板子上,如下图:
在这里插入图片描述
求所需的最小的支柱的长度

思路

因为数据小的原因可以采取 O ( n 2 ) O(n^2) O(n2)的简单做法,但因为学习线段树中,故给出线段树的解法

先以板子的高度进行排序,然后后面的板子必在高处,判断两端下方的位置是否有板子后修改即可
即为单点查询,区间修改

在处理边界时,发现容易误判,采取大佬的想法:
查[l,l+1] 与 [r-1,r]时,这就会使边界相交的板子误判可插钉,事实上差0.5个单位长度
我们此题的(l,r)是开区间,我的线段树是闭区间,那么可以令我区间修改时,不修改[l,r] 而是修改[l+1,r-1] 这样就相当于开区间了。

AC Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e4+9;
struct node{
    int y, x1, x2;
}a[N];
struct segtree{
    int v, tag;
}tr[N<<2];
inline int read()
{
    int ans=0;
    char last=' ',ch=getchar();
    while(ch<'0'||ch>'9') last=ch,ch=getchar();
    while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar();
    if(last=='-') ans=-ans;
    return ans;
}
inline int lc(int p)   {return p<<1;}
inline int rc(int p)   {return p<<1|1;}
inline void build(int k, int l, int r){
    if(l==r)    return ;
    int mid=(l+r)>>1;
    build(lc(k), l, mid);
    build(rc(k), mid+1, r);
}
inline void f(int p, int k){
    tr[p].v=max(tr[p].v, k);
    tr[p].tag=max(tr[p].tag, k);
}
inline void push_down(int p){
    f(lc(p), tr[p].tag);
    f(rc(p), tr[p].tag);
    tr[p].tag=0;
}
inline void push_up(int p)  {tr[p].v=max(tr[lc(p)].v, tr[rc(p)].v);}
inline void updata(int p, int l, int r, int x, int y, int k){
    if(x>r || y<l)  return ;
    if(l<=x && y<=r){
        tr[p].v=max(tr[p].v, k);
        tr[p].tag=max(tr[p].tag,k);
        return ;
    }  
    int mid=(x+y)>>1;
    if(tr[p].tag) push_down(p);
    updata(lc(p), l, r, x, mid, k);
    updata(rc(p), l, r, mid+1, y, k);
    push_up(p);
}
inline int query(int p, int l, int r, int x, int y){
    if(x>r || y<l)  return 0;
    if(l<=x && y<=r) return tr[p].v;
    int mid=(x+y)>>1;
    if(tr[p].tag) push_down(p);
    return max(query(lc(p), l, r, x, mid), query(rc(p), l, r, mid+1, y));
}
inline bool cmp(node a, node b){
    return a.y<b.y;
}
int main(){
    int n=read();
    ll ans=0;
    for(int i=1; i<=n; i++){
        a[i].y=read();
        a[i].x1=read();
        a[i].x2=read();
    }
    sort(a+1, a+1+n, cmp);
    build(1,1,N);
    int h;
    for(int i=1; i<=n; i++){
        h=query(1,a[i].x1,a[i].x1+1, 1, N);
        ans+=(a[i].y-h);
        h=query(1,a[i].x2-1,a[i].x2, 1, N);
        ans+=(a[i].y-h);
        updata(1,a[i].x1+1, a[i].x2-1, 1, N, a[i].y);
    }
    cout<<ans<<endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值