SKYLINE
题目链接:
解题思路:
题目大意:
我们要在地平线(看成数轴)上依次建造n座建筑物。建筑物的修建按照从后往前的顺序,因此新建筑物可能会挡住一部分老建筑物。
修建完一座建筑物之后,统计它在多长的部分是最高的(可以和其他建筑物并列最高),并把这个长度称为该建筑物的“覆盖度”。如下图所示,假定最先修建的是灰色建筑物,然后是黑色,最后时白色,则三者的覆盖度依次为6,4,4.例如,白色建筑物在3-5,11-13是最高的,因此覆盖度为(5-3)+(13-11)=4.求所有建筑物的总覆盖度。
算法思想:
线段树的区间修改,每次插入一条线段并查询,如果当前要覆盖的高度是大于之前最大高度就覆盖掉,否则维持现状。如果该线段覆盖的区间的最高值小于插入的线段,那么计算长度的时候遇到一条线段会被分开,需要r--,不然处理起来会很麻烦。。。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 100005;
const int NN = 100000;
struct node{
int l,r,maxn;
int lazy;
}tree[N<<2];
int sum;
void build(int id,int l,int r){
tree[id].l = l;
tree[id].r = r;
tree[id].maxn = 0;
tree[id].lazy = 1;
if(l == r)
return ;
int mid = (l+r)>>1;
build(id<<1,l,mid);
build(id<<1|1,mid+1,r);
}
void pushdown(int id){
if(tree[id].lazy){
tree[id<<1].maxn = tree[id<<1|1].maxn = tree[id].maxn;
tree[id].lazy = 0;
}
}
void update(int id, int l, int r, int h){
if(tree[id].l == l && tree[id].r == r && tree[id].lazy){
if (h > tree[id].maxn)
tree[id].maxn = h;
return;
}
pushdown(id);
int mid = (tree[id].l+tree[id].r)>>1;
if(r <= mid)
update(id<<1,l,r,h);
else if (l > mid)
update(id<<1|1,l,r,h);
else {
update(id<<1,l,mid,h);
update(id<<1|1,mid+1,r,h);
}
tree[id].maxn = max(tree[id<<1].maxn,tree[id<<1|1].maxn);
}
int query(int id,int l,int r,int h){
if(tree[id].lazy){
if(tree[id].maxn <= h){
update(id,l,r,h);
return r-l+1;
}
else
return 0;
}
pushdown(id);
int mid = (tree[id].l+tree[id].r)>>1;
if(r <= mid)
return query(id<<1,l,r,h);
else if (l > mid)
return query(id<<1|1,l,r,h);
else
return query(id<<1,l,mid,h) + query(id<<1|1,mid+1,r,h);
tree[id].maxn = max(tree[id<<1].maxn,tree[id<<1|1].maxn);
}
int main(){
int T,n;
scanf("%d",&T);
while(scanf("%d",&n),n){
int ans = 0;
build(1,1,NN);
int l,r,h;
for(int i = 0; i < n; i++){
scanf("%d%d%d",&l,&r,&h);
r--;
sum = query(1,l,r,h);
ans += sum;
}
printf("%d\n",ans);
}
return 0;
}