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