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;
}
比如我们最先插入(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 3667 线段树 + 延迟标记 + 区间处理
- poj 3225 Help with Intervals -线段树-延迟标记-区间交并补
- POJ 2528 线段树(离散化+延迟标记)
- POJ 3468 A Simple Problem with Integers(线段树,延迟标记)
- POJ 3468 A Simple Problem with Integers(线段树 ,延迟标记)
- Poj 3468 A Simple Problem with Integers(线段树 区间更新 延迟标记)
- POJ 2528 线段树 + 延迟标记 + 离散化
- 线段树模板 (poj 3468)延迟标记
- POJ 3468 线段树成段更新区间求和 + 延迟标记详解 A Simple Problem with Integers
- poj 3468 A Simple Problem with Integers(线段树成段更新,延迟标记,Lazy)
- POJ 3667 Hotel(线段树+区间合并+延迟标记)
- poj 3468 A Simple Problem with Integers 线段树加延迟标记
- poj 1436 Horizontally Visible Segments(线段树)(第二部分成段更新 不需要延迟标记 )
- poj 3468 线段树延迟标记
- poj 3667 hotel - 线段树-区间更新-延迟标记
- poj 3468 线段树,延迟标记法
- [ACM] poj 3468 A Simple Problem with Integers(线段树,成段更新,懒惰标记)
- poj 3468 线段树 lazy标记模板
- POJ 3237 Tree(树链剖分 线段树区间标记)
- poj 3277...离散化+线段树...