https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2109
题目大意:
我们要在地平线(看成数轴)上依次建造n座建筑物。建筑物的修建按照从后往前的顺序,因此新建筑物可能会挡住一部分老建筑物。
修建完一座建筑物之后,统计它在多长的部分是最高的(可以和其他建筑物并列最高),并把这个长度称为该建筑物的“覆盖度”。如下图所示,假定最先修建的是灰色建筑物,然后是黑色,最后时白色,则三者的覆盖度依次为6,4,4.例如,白色建筑物在3-5,11-13是最高的,因此覆盖度为(5-3)+(13-11)=4.求所有建筑物的总覆盖度。
算法思想:
线段树的区间修改,每次插入一条线段并查询,如果当前要覆盖的高度是大于之前最大高度就覆盖掉,否则维持现状。如果该线段覆盖的区间的最高值小于插入的线段,那么计算长度的时候遇到一条线段会被分开,需要r--,不然处理起来会很麻烦。。。
#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; }