平板
一个空间中,给你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] 这样就相当于开区间了。
#include
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;
}