我一开始没有想到用线段树,是我学得太僵了...
我们要记录每段的最大高度,而且要组织成区间信息,这要用到线段树
怎么用呢?
线段树维护区间最大值;对于每个线段,先二分至其包含区间,如果最大值>=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; }