P1382 楼房
在同一横坐标,轮廓只会被最高的楼房影响
所以考虑用 $multiset$ 维护当前的每个楼房高度
轮廓线显然只有出现楼房最高高度变化时会出现转折点
把一个楼根据左右边界分成两个东西,左边时把高度加入 $set$,到了右边再从 $set$ 里把该高度删除
每次更新 $set$ 时判断一下高度变化并记录答案就好了
注意每次插入或删除时要把同一横坐标的一起完成,因为同一横坐标最多只会产生一次贡献
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<set> using namespace std; typedef long long ll; inline int read() { int x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } const int N=1e6+7; int n,m; int ans[N][2],tot; struct dat{ int x,y; inline bool operator < (const dat &tmp) const { return x<tmp.x; } }d[N]; multiset <int> S; int main() { int a,b,c; n=read(); for(int i=1;i<=n;i++) { a=read(),b=read(),c=read(); d[++m].x=b; d[m].y=a; d[++m].x=c; d[m].y=-a;//把楼房拆成两部分 } sort(d+1,d+m+1);//按横坐标排序 S.insert(0); int h=0,j=0,t=0;//h是当前高度 for(int i=1;i<=m;)//从左到右一个个考虑 { for(j=i;j<=m;j++)//要把同一横坐标的一起插入或删除 { if(d[j].x>d[i].x) break; if(d[j].y>0) S.insert(d[j].y); else S.erase(S.find(-d[j].y)); } t=(*S.rbegin());//rbegin指向集合最后一个数,即最大值 if(t!=h)//有高度变化才能计算答案 { ans[++tot][0]=d[i].x; ans[tot][1]=h; ans[++tot][0]=d[i].x; ans[tot][1]=t; h=t; } i=j; } printf("%d\n",tot); for(int i=1;i<=tot;i++) printf("%d %d\n",ans[i][0],ans[i][1]); return 0; }