您的位置:首页 > 其它

POJ 3277 线段树 + 延迟标记

2016-11-25 14:35 274 查看
本题就是给出一堆矩形,然后让我们算总共的面积,也就是重复的面积只算一次。需要用到线段树,每次输入矩形的左端点和右端点,还有高。我们就把这条线段插进去,线段的高度取较高的那一个。注意到这和普通的线段树不太一样,普通的情况是,当我们插入的线段完全覆盖线段树中的某一条线段时,那条线段的值就被更新成插入的线段的值。但是本题的情况却不太一样,当我们插入的线段完全覆盖线段树的某一条线段时,如果现在的权值大于原有线段的权值,就将其覆盖。但是一定要注意,更新之后的线段树的值并不一定是正确的。

比如我们最先插入(1,5),5。然后打上延迟标记。第二次插入(1,3),7。所以我们就把延迟标记下移。(1,3)和(3,5)都更新成5,然后(1,3)变成7。然后再把(1,5)更新成6。现在假如我们来查询,难道(1,5)的值就是6吗?明显不是,(1,3)区间的权值是7,(3,5)区间的值为5。那么怎么才能查询到正确的结果呢?只需要从根节点,不断的往叶子节点更新就行了。

所以这道题:

1.更新的时候延迟标记下移的规则不是完全覆盖,是取一个区间中的最大值

2.查询的时候,从根节点往叶子节点更新

3.本题线段树叶子节点应该构建成(x,x + 1)的形式,不然会漏掉[m,m + 1]的面积

#include <algorithm>
#include <iostream>
#include <iterator>
#include <sstream>
#include <fstream>
#include <istream>
#include <ostream>
#include <complex>
#include <cstring>
#include <utility>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <string>
#include <cctype>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <new>
#include <set>
#include <map>
#define lson l, m, k << 1
#define rson m, r, k << 1| 1

using namespace std;

typedef long long int LL;
const int INF = 0x3f3f3f3f;
const int maxn = 200000 << 2;
LL cover[maxn], maxh[maxn], li[maxn], ri[maxn], hi[maxn], x[maxn];

void pushdown(int k){
if (cover[k]){
if (maxh[k << 1] < maxh[k]){
maxh[k << 1] = maxh[k];
cover[k << 1] = 1;
}
if (maxh[k << 1 | 1] < maxh[k]){
maxh[k << 1 | 1] = maxh[k];
cover[k << 1 | 1] = 1;
}
cover[k] = 0;
}
}

void update(int l, int r, int k, int L, int R, int H){
if (L == l && R == r){
if (maxh[k] < H){
maxh[k] = H;
cover[k] = 1;
}
return;
}
pushdown(k);
int m = (l + r) >> 1;
if (R <= m) update(lson, L, R, H);
else if (L >= m) update(rson, L, R, H);
else{
update(lson, L, m, H);
update(rson, m, R, H);
}
}

LL query(int l, int r, int k){
if (l == r - 1) return maxh[k] * (x[r] - x[l]);
maxh[k << 1] = max(maxh[k], maxh[k << 1]);
maxh[k << 1 | 1] = max(maxh[k], maxh[k << 1 | 1]);
int m = (l + r) >> 1;
return query(lson) + query(rson);
}

int Binary_Search(int s, int e, int key) {
int left = s, right = e, mid;
while (left <= right) {
mid = (left + right) >> 1;
if (x[mid] >= key) right = mid - 1;
else left = mid + 1;
}
if (x[left] == key) return left;
return -1;
}

int main()
{
//freopen("1.txt", "r", stdin);
int n;
scanf ("%d", &n);
int nn = 0;
for (LL i = 1; i <= n; i++) {
scanf ("%I64d%I64d%I64d", &li[i], &ri[i], &hi[i]);
x[++nn] = li[i];
x[++nn] = ri[i];
}

memset(maxh, 0, sizeof(maxh));//建树
memset(cover, 0, sizeof(cover));

sort(x + 1, x + nn + 1);//离散化
int len = unique(x + 1, x + nn + 1) - (x + 1);
for (LL i = 1; i <= n; i++) {
LL l = Binary_Search(1, len + 1, li[i]);
LL r = Binary_Search(1, len + 1, ri[i]);
update(1, len, 1, l, r, hi[i]);
}

printf("%I64d\n", query(1, len, 1));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  POJ 3277 线段树 csdn