luogu P1904 天际线

分析

都知道是从左向右扫描
可是该维护什么,扫描什么?
注意想想怎么输出, 实际上它要的输出就是图形的轮廓,即每个突出块的左上节点的x,y
所以说, 我们可以把扫描线扫进的楼房放入线段树,扫出的楼房删去(也就是把它高度清零)
然后维护线段树内的最大值
( 为什么这样想呢: 因为要输出的是轮廓,所以我们这样维护后,既可以在在高度突变时及时输出答案,
又不会受到以前楼房的高度的影响)

思考后有需要请看

细节详见代码&注释

#include<cstdio>
#include<algorithm>
using namespace std;
#define MAX 5000+9

int id, lastt, m;

struct node{
    int x, h, id;//id后面有用
    bool operator < (const node& xxx) const {
        return x < xxx.x;
    }
}a[MAX<<2];
int mx[MAX<<2];

void build(int o, int l, int r) {
    if(l == r) {mx[o] = 0; return ;}
    int mid = (l+r)>>1;
    build(o<<1, l, mid);
    build(o<<1|1, mid+1, r);
    mx[o] = 0;//应该是因为没有扫,所以是0
}

void update(int o,int l, int r, int t, int v) {
    if(l == r) {
        mx[o] = v;
        return ;
    }
    int mid = (l+r)>>1;
    if(t <= mid) update(o<<1, l, mid, t, v);
    else update(o<<1|1, mid+1, r, t, v);
    mx[o] = max(mx[o<<1] , mx[o<<1|1]);
}


int main() {
    int l,h,r;
	while(scanf("%d%d%d",&l,&h,&r)!=EOF)
	{
		id++;
		a[++m].x=l,a[m].h=h,a[m].id=id;
		a[++m].x=r,a[m].h=-h,a[m].id=id;//扫描线用正负表示进出
	}
	sort(a+1, a+m+1);
    build(1, 1, id);
    for(int i = 1; i <= m; i++) {
        if(a[i].h > 0) update(1, 1, id, a[i].id, a[i].h);
        else update(1, 1, id, a[i].id, 0);
        if(a[i].x != a[i+1].x ) {//如果这个点处理完了才继续执行...为了防止在处理两个并排的不一样高的楼房时(假设左边低一点),
            // 交点没有处理完, 导致last改变为0, 导致错解
            if(lastt != mx[1] ) printf("%d %d ", a[i].x , mx[1]);//只输出第一个改变点的x和y
            lastt = mx[1];//更新最高值, 用于判断转折点
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/tyner/p/11243268.html