题意:有一条街上要盖高楼,按先后顺序给出要建的楼的左右范围和高度,在修完一个建筑后,统计它在多长的部分是最高的(并列最高也可以),叫做覆盖度,要求把所有的建筑物的覆盖度和求出来。
题解:线段树区间修改,如果当前要覆盖的高度是大于之前最大高度就覆盖掉,否则维持现状,为了减少判断,可以把最小高度也求出来,如果小于最小高度直接return。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N = 100000;
int ma[N * 4], mi[N * 4], seth[N * 4], temp, n, l1, r1, h1;
void pushup(int k, int left, int right) {
int lc = k * 2, rc = k * 2 + 1;
if (left < right) {
ma[k] = max(ma[k * 2], ma[k * 2 + 1]);
mi[k] = min(mi[k * 2], mi[k * 2 + 1]);
}
if (seth[k])
ma[k] = mi[k] = seth[k];
}
void pushdown(int k) {
if (seth[k]) {
seth[k * 2] = seth[k * 2 + 1] = seth[k];
seth[k] = 0;
}
}
void query(int k, int left, int right) {
int lc = k * 2, rc = k * 2 + 1;
if (l1 <= left && right <= r1) {
if (ma[k] <= h1) {
temp += right - left + 1;
seth[k] = h1;
pushup(k, left, right);
return;
}
else if (mi[k] > h1 || left == right)//剪枝
return;
}
int mid = (left + right) / 2;
pushdown(k);
pushup(lc, left, mid);
pushup(rc, mid + 1, right);
if (l1 <= mid)
query(lc, left, mid);
if (r1 > mid)
query(rc, mid + 1, right);
pushup(k, left, right);
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
memset(ma, 0, sizeof(ma));
memset(mi, 0, sizeof(mi));
memset(seth, 0, sizeof(seth));
scanf("%d", &n);
int res = 0;
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &l1, &r1, &h1);
r1--;//段覆盖而不是点覆盖
temp = 0;
query(1, 1, N);
res += temp;
}
printf("%d\n", res);
}
return 0;
}