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; }