首页 > 其他 > 详细

poj 3468 线段树

时间:2015-04-06 14:06:42      阅读:167      评论:0      收藏:0      [点我收藏+]

线段树的 建立build(初始化+左右相等+两个递归+别忘了sum)+更新update(递归出口+更新delta+三向递归+修正当前节点的value)+查找query(如果左右相等+更新delta+三种递归)

#include<iostream>
using namespace std;

#define L(root) ((root) << 1)
#define R(root) (((root) << 1) + 1)

const int MAXN = 100001;
int numbers[MAXN];

struct st {
    // 区间范围
    int left, right;
    // 更新值、区间总和
    long long delta, sum;
} st[MAXN * 4];

// 建树代码基本不变
void build(int root, int l, int r) {
    st[root].left = l, st[root].right = r, st[root].delta = 0;
    if (l == r) {
        st[root].sum = numbers[l];
        return;
    }

    int m = l + ((r - l) >> 1);
    build(L(root), l, m);
    build(R(root), m + 1, r);
    st[root].sum = st[L(root)].sum + st[R(root)].sum;
}

long long query(int root, int l, int r) {
    // 如查询区间恰等于节点区间,直接返回该区间总和即可
    if (st[root].left == l && st[root].right == r) {
        return st[root].sum;
    }

    // 否则需将当前区间的“缓冲”值更新下去并修正各节点区间的总和
    if (st[root].delta) {
        st[L(root)].delta += st[root].delta;
        st[R(root)].delta += st[root].delta;
        st[L(root)].sum += st[root].delta * (st[L(root)].right - st[L(root)].left + 1);
        st[R(root)].sum += st[root].delta * (st[R(root)].right - st[R(root)].left + 1);
        st[root].delta = 0;
    }

    int m = st[root].left + ((st[root].right - st[root].left) >> 1);
    if (r <= m) {
        return query(L(root), l, r);
    } else if (l > m) {
        return query(R(root), l, r);
    } else {
        return query(L(root), l, m) + query(R(root), m + 1, r);
    }
}

void update(int root, int l, int r, long long v) {
    // 如变更区间恰等于节点区间,只修正当前节点区间即可
    if (st[root].left == l && st[root].right == r) {
        st[root].delta += v;
        st[root].sum += v * (r - l + 1);
        return;
    }

    // 否则需向下修正相关节点区间
    if (st[root].delta) {
        st[L(root)].delta += st[root].delta;
        st[R(root)].delta += st[root].delta;
        st[L(root)].sum += st[root].delta * (st[L(root)].right - st[L(root)].left + 1);
        st[R(root)].sum += st[root].delta * (st[R(root)].right - st[R(root)].left + 1);
        st[root].delta = 0;
    }

    int m = st[root].left + ((st[root].right - st[root].left) >> 1);
    if (r <= m) {
        update(L(root), l, r, v);
    } else if (l > m) {
        update(R(root), l, r, v);
    } else {
        update(L(root), l, m, v);
        update(R(root), m + 1, r, v);
    }
    // 同时一定要记得修正当前节点区间的总和
    st[root].sum = st[L(root)].sum + st[R(root)].sum;
}

int main() {
    int N, Q;
    while (cin >>N >> Q) {
        for (int i = 1; i <= N; ++i) {
            cin >> numbers[i];
        }

        build(1, 1, N);

        char cmd;
        int l, r;
        long long v;
        while (Q--) {
            cin >>cmd;
            cin >>l>>r;
            switch (cmd) {
            case Q:
                cout<<query(1, l, r)<<endl;
                break;

            case C:
                cin >> v;
                if (v) {
                    update(1, l, r, v);
                }
                break;
            }
        }
    }

    return 0;
}

 

poj 3468 线段树

原文:http://www.cnblogs.com/lipenglin/p/4395743.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!