线段树lazy标记

来源:互联网 发布:蜂云网络 编辑:程序博客网 时间:2024/05/16 03:39

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;}
原创粉丝点击