|
题目链接:http://acm.fzu.edu.cn/problem.php?pid=1608
 /**//*

题意:
给定M个区间 (1 <= M <= 500000)和这些区间上的权值,求最终并区间的最
大权值总和(某个区间不能被计算两次)。

解法:
线段树

思路:
因为最后询问只有一次,而多次的插入操作,所以这个问题有个很简单的解
决办法,每次更新的时候只更新到区间完全覆盖的情况,这样的复杂度是log(n)
的,而最后询问的时候来一次O(nlogn)的操作,一直查询到元区间,每次将当前
区间的最大值向下传递给两个儿子。统计时只要统计元区间的最值和即可。
*/

#include <iostream>

using namespace std;

#define maxn 50010

 struct Tree {
int Max;
int root, l, r;

void CoverBy(int lazy);
 int len() {
return r - l;
}
}T[maxn*4];

int n, m;
 void Build(int root, int l, int r) {
T[root].root = root;
T[root].l = l;
T[root].r = r;
T[root].Max = 0;
 if(l + 1 == r || l == r) {
return ;
}
int mid = (l + r) >> 1;
Build(root<<1, l, mid);
Build(root<<1|1, mid, r);
}

 void Tree::CoverBy(int lazy) {
 if(lazy > Max) {
Max = lazy;
}
}

 void Insert(int root, int l, int r, int val) {
 if(l >= T[root].r || r <= T[root].l) {
return ;
}
 if(l <= T[root].l && T[root].r <= r) {
T[root].CoverBy(val);
return ;
}
Insert(root<<1, l, r, val);
Insert(root<<1|1, l, r, val);
}

 int Query(int root, int l, int r) {
 if(l + 1 == r) {
return T[root].Max;
}
T[root<<1].CoverBy(T[root].Max);
T[root<<1|1].CoverBy(T[root].Max);

int mid = (l + r) >> 1;
return Query(root<<1, l, mid) + Query(root<<1|1, mid, r);
}

 int main() {
int i;
 while(scanf("%d %d", &n, &m) != EOF) {
Build(1, 0, n);
 for(i = 0; i < m; i++) {
int x, y, z;
scanf("%d %d %d", &x, &y, &z);
Insert(1, x, y, z);
}
printf("%d\n", Query(1, 0, n));
}

return 0;
}
|