http://poj.org/problem?id=3468
线段树的核心就是build,query,update,其中update又分为单点更新和区间更新,在区间更新的过程中,如果一路更新到底可能会造成时间消耗很大,而后续的询问并没有用到,这样就造成了资源的浪费,lazy就在这里发挥作用。
在update的过程中如果找到了update的区间(比如2-5),那就把2-5的区间的sum值修改就好了,如果按照正常的思维,这时应该把2-5所在的子区间也全部更新,但是在后续的query中可能并没有用到以下的这些更新值,那么就先不用更新,先用lazy把它存起来。
这样的后果就是在下次询问(query)的过程中,如果有遇到lazy值不为0,也就是有一些更新还没有完成的情况时,就需要把lazy值给释放出来,向下更新一下。
另外在线段树中,区间更新和单点更新得区别就在于update函数,单点更新,位置只能位于一个区间内,而区间更新,这个区间极有可能位于跨度两个区间,这需要注意。
还有写线段树时,pushup和pushdown函数是刚学的,觉得可以让程序更简单易懂,现在渐渐感觉到每个人写程序的风格都是不一样的,一个比较好的算法实现流程可能差不多,但是自己代码的模板是不一样的。
下面的链接是我学习线段树很有力的帮助,博主代码风格简洁,整理的例题也很到位,很喜欢~虽然有些代码还是有些问题……但是适合像我这样萌新(菜鸟),hhh,分享给大家。
http://blog.csdn.net/metalseed/article/details/8039326
POJ3468AC代码
#include<iostream>
using namespace std;
const int maxn = 100005;
struct Tree
{
int left, right;
long long sum;
long long lazy;
}tree[maxn*4];
long long a[maxn];
void pushup(int root)
{
tree[root].sum = tree[root * 2].sum + tree[root * 2 + 1].sum;
}//向上更新父节点
void pushdown(int root, int m)
{
if (tree[root].lazy)
{
tree[root * 2].lazy += tree[root].lazy;
tree[root * 2 + 1].lazy += tree[root].lazy;
tree[root * 2].sum += tree[root].lazy*(m - (m / 2));
tree[root * 2 + 1].sum += tree[root].lazy*(m / 2);
tree[root].lazy = 0;
}
}//向下更新,lazy关键
void build(int root, int start, int end)
{
tree[root].lazy = 0;
tree[root].left = start;
tree[root].right = end;
if (start == end)
{
tree[root].sum = a[start];
return;
}
int mid = (start + end) / 2;
build(root * 2, start, mid);
build(root * 2 + 1, mid + 1, end);
pushup(root);
}
void update(int root,int start,int end,int value)
{
if (start <= tree[root].left&&tree[root].right <= end)
//区间的更新,这句话的意思与start == tree[root].left&&tree[root].right == end相同
{
tree[root].lazy += value;
tree[root].sum += (long long)value*(tree[root].right - tree[root].left + 1);
return;
//lazy关键
}
/*if (tree[root].left == tree[root].right)
return;*/
pushdown(root, tree[root].right - tree[root].left + 1);
int mid = (tree[root].right + tree[root].left) / 2;
if (end <= mid)
update(root * 2, start, end, value);
else
if (start >= mid + 1)
update(root * 2 + 1, start, end, value);
else
{
update(root * 2, start, mid, value);
update(root * 2 + 1, mid + 1, end, value);
}//区间更新与单点更新的不同就是多了这个else
pushup(root);
}
long long query(int root,int start,int end)
{
if (start <= tree[root].left&&tree[root].right <= end)
return tree[root].sum;
pushdown(root, tree[root].right - tree[root].left + 1);
//lazy,然后现在需要调用这个值,就要更新
int mid= (tree[root].right + tree[root].left) / 2;
long long reu = 0;
if (end <= mid)
reu += query(root * 2, start, end);
else
if (start >= mid + 1)
reu += query(root * 2 + 1, start, end);
else
reu = query(root * 2, start, mid) + query(root * 2 + 1, mid+1, end);
return reu;
}
int main()
{
int n, q;
while (cin >> n >> q)
{
int i;
for (i = 1; i <= n; i++)
cin >> a[i];
build(1, 1, n);
while (q--)
{
char order;
int a, b, c;
cin >> order;
if (order == 'Q')
{
cin >> a >> b;
cout << query(1, a, b) << endl;
}
else
if(order=='C')
{
cin >> a >> b >> c;
update(1, a, b, c);
}
}
}
return 0;
}