【题解】
本题要计算矩形组成的轮廓线,可以用线段树来实现。
由于区间长度很大,不能直接开线段数记录,我们要先进行离散化。(显然拐点只可能出现在矩形的左右两边上)然后逐个加入矩形并维护每个位置的最大值。最后对每个拐点可能的位置进行查询并统计答案即可。
1 #include<cstdio> 2 #include<algorithm> 3 #define ls (u<<1) 4 #define rs (u<<1|1) 5 #define mid ((a[u].l+a[u].r)>>1) 6 using namespace std; 7 const int maxn=800010; 8 int n,N,m,h[maxn],l[maxn],r[maxn],l0[maxn],r0[maxn],s[maxn]; 9 struct tree{int l,r,max,del;}a[maxn]; 10 struct point{int x,y;}ans[maxn]; 11 inline int read(){ 12 int k=0,f=1; char c=getchar(); 13 while(c<'0'||c>'9')c=='-'&&(f=-1),c=getchar(); 14 while('0'<=c&&c<='9')k=k*10+c-'0',c=getchar(); 15 return k*f; 16 } 17 void build(int u,int l,int r){ 18 a[u].l=l; a[u].r=r; a[u].max=0; 19 if(l<r) build(ls,l,mid),build(rs,mid+1,r); 20 } 21 void pushdown(int u){ 22 a[ls].max=max(a[ls].max,a[u].del); a[rs].max=max(a[rs].max,a[u].del); 23 a[ls].del=max(a[ls].del,a[u].del); a[rs].del=max(a[rs].del,a[u].del); a[u].del=0; 24 } 25 void update(int u,int l,int r,int del){ 26 if(l<=a[u].l&&a[u].r<=r){a[u].max=max(a[u].max,del); a[u].del=max(a[u].del,del); return;} 27 pushdown(u); 28 if(l<=mid) update(ls,l,r,del); 29 if(r>mid) update(rs,l,r,del); 30 a[u].max=max(a[ls].max,a[rs].max); 31 } 32 int query(int u,int pos){ 33 if(a[u].l==a[u].r) return a[u].max; 34 pushdown(u); 35 if(pos<=mid) return query(ls,pos); else return query(rs,pos); 36 } 37 inline void Prepare(){ 38 m=read(); 39 for(int i=1;i<=m;i++) h[i]=read(),s[++n]=l0[i]=read(),s[++n]=r0[i]=read(); 40 sort(s+1,s+1+n); N=unique(s+1,s+1+n)-s-1; 41 for(int i=1;i<=m;i++) 42 l[i]=lower_bound(s+1,s+1+N,l0[i])-s, 43 r[i]=lower_bound(s+1,s+1+N,r0[i])-s; 44 } 45 int main(){ 46 Prepare(); build(1,1,N+1); 47 for(int i=1;i<=m;i++) update(1,l[i],r[i]-1,h[i]); 48 // for(int i=1;i<=N+1;i++) printf("%d ",query(1,i)); 49 int last=0,tot=0; 50 for(int i=1;i<=N+1;i++){ 51 int now=query(1,i); 52 if(now!=last){ 53 ans[++tot]=(point){s[i],last}; 54 ans[++tot]=(point){s[i],now}; 55 } 56 last=now; 57 } 58 printf("%d ",tot); 59 for(int i=1;i<=tot;i++) printf("%d %d ",ans[i].x,ans[i].y); 60 return 0; 61 }