Luogu P1904 天际线

题面

复习一下线段树

将城市变成轮廓线,每一个位置的高度自然选的是该位置高度的最大值

维护这个东西,你可以用各种各样的东西,比如线段树

因为数据范围小,不需要离散化,但是建议写离散化练手这个人太蒻了竟然没写,打他

我们以每个位置为线段的节点,造一颗线段树,因为没有初值,像我这样的线段树不需要建树

输出弄得很高级,其实就是输出第奇数个点的坐标,这样偶数点的判断也不需要了

贴上代码:

#include<bits/stdc++.h>
using namespace std;
int n,h[(int)1e4+7];
// max 版的线段树,细节注意
// 线段树其实并不是很长,实在要打错建议先敲五,六次模板,作者过来人了
int t[((int)1e4+7)<<2],tag[((int)1e4+7)<<2]; // 常规: 数组开四倍
inline int lc(int p) {return p<<1;}
inline int rc(int p) {return p<<1|1;}
inline void push_up(int p) {t[p] = max(t[lc(p)],t[rc(p)]);}
inline void f(int p,int k) {                 // 这样写可能开销会稍微大一点点,但是比较直观
	t[p] = max(t[p],k);
	tag[p] = max(tag[p],k);
}
inline void push_down(int p) {
	f(lc(p),tag[p]);
	f(rc(p),tag[p]);
	tag[p] = 0;
}
inline void updata(int p,int l,int r,int nl,int nr,int k) {
	if(nl>r || nr<l) return ;            // 边界处理,可以在递归前判断,开销会变小
	if(l<=nl&&nr<=r) {t[p] = max(t[p],k),tag[p] = max(tag[p],k);return ;}
	int mid = (nl+nr) >> 1;
	if(tag[p]) push_down(p);
	updata(lc(p),l,r,nl,mid,k);
	updata(rc(p),l,r,mid+1,nr,k);
	push_up(p);
}
inline int  query(int p,int l,int r,int nl,int nr) {
	if(nl>r || nr<l) return 0;           // 同上
	if(l<=nl&&nr<=r) return t[p];
	int mid = (nl+nr) >> 1;
	if(tag[p]) push_down(p);
	return max(query(lc(p),l,r,nl,mid),query(rc(p),l,r,mid+1,nr));
}
int x[(int)1e4+7],y[(int)1e4+7],z[(int)1e4+7];
int main() {
	while(~scanf("%d",&x[++n])) scanf("%d%d",&y[n],&z[n]);--n;
	for(int i=1;i<=n;++i) updata(1,x[i],z[i]-1,1,(int)1e4,y[i]);
	for(int i=1;i<=(int)1e4;++i) h[i] = query(1,i,i,1,(int)1e4);              // 求出每一个点的最大值
	for(int i=1;i<=(int)1e4;++i) if(h[i] != h[i-1]) printf("%d %d ",i,h[i]);  // 只要和上一个位置大小不同,就说明是第奇数个点
	return 0;
}
原文地址:https://www.cnblogs.com/Ax-Dea/p/12620615.html