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

 

posted @ 2019-02-01 13:27  LLTYYC  阅读(124)  评论(0编辑  收藏  举报