线段树

线段树 1:单点修改,区间查询

代码:

/* Segment Tree 1
 * Au: GG
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;

const int N = 500005;

int n, m, data[N];

struct tree {
    int l, r;
    ll sum;
} tr[N << 2]; // 四倍大小

void build(int x, int y, int i) {
    tr[i].l = x, tr[i].r = y;

    if (x == y) tr[i].sum = data[x]; // 叶子节点直接赋值
    else {
        int mid = (x + y) >> 1;
        build(x, mid, i<<1); // 左子树
        build(mid + 1, y, i<<1|1); // 右子树
        tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
    }
}

void update(int x, int val, int i) {
    if (tr[i].l == x && tr[i].r == x) // 找到了叶子
        tr[i].sum += val;
    else {
        int mid = (tr[i].l + tr[i].r) >> 1;
        if (x <= mid)
            update(x, val, i<<1);
        else if (x > mid)
            update(x, val, i<<1|1);
        tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
    }
}

ll query(int x, int y, int i) {
    if (x <= tr[i].l && y >= tr[i].r) // 当前结点的区间完全被目标区间包含
        return tr[i].sum;
    else {
        int mid = (tr[i].l + tr[i].r) >> 1;
        if (x > mid) // 完全在右儿子
            return query(x, y, i<<1|1);
        else if (y <= mid) // 完全在左儿子
            return query(x, y, i<<1);
        else // 目标区间在左右都有分布
            return query(x, y, i<<1) + query(x, y, i<<1|1);
    }
}

int main() {
    scanf("%d", &n);
    scanf("%d", &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &data[i]);
    build(1, n, 1);

    while (m--) {
        int op, a, b;
        scanf("%d", &op);
        if (op == 1) { // 单点修改
            scanf("%d%d", &a, &b);
            update(a, b, 1);
        }
        else { // 区间求和
            scanf("%d%d", &a, &b);
            printf("%lld\n", query(a, b, 1));
        }
    }

    return 0;
}

线段树 2:区间修改,区间查询

代码:

/* Segment Tree 2
 * Au: GG
 */
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <ctime>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;

const int N = 500005;

int n, m, data[N];

struct tree {
    int l, r;
    ll sum, lazy;
} tr[N << 2]; // 四倍大小

void build(int x, int y, int i) {
    tr[i].l = x, tr[i].r = y;

    if (x == y) tr[i].sum = data[x]; // 叶子节点直接赋值
    else {
        int mid = (x + y) >> 1;
        build(x, mid, i<<1); // 左子树
        build(mid + 1, y, i<<1|1); // 右子树
        tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
    }
}

void push_down(int i, int m) {
	if (tr[i].lazy) {
		tr[i<<1].lazy += tr[i].lazy;
		tr[i<<1|1].lazy += tr[i].lazy;
		tr[i<<1].sum += tr[i].lazy * (m - (m >> 1));
		tr[i<<1|1].sum += tr[i].lazy * (m >> 1);
		tr[i].lazy = 0;
	}
}

void update(int x, int y, int val, int i) {
    if (tr[i].l >= x && tr[i].r <= y) { // 目标区间完全被覆盖
        tr[i].lazy += val;
        tr[i].sum += val * (tr[i].r - tr[i].l + 1);
        return;
    }
    else {
    	push_down(i, tr[i].r - tr[i].l + 1); // 分解下传延迟信息
        int mid = (tr[i].l + tr[i].r) >> 1;
        if (y <= mid)
            update(x, y, val, i<<1);
        else if (x > mid)
            update(x, y, val, i<<1|1);
        else
        	update(x, y, val, i<<1|1), update(x, y, val, i<<1);
        tr[i].sum = tr[i<<1].sum + tr[i<<1|1].sum; // 回溯时维护区间和
    }
}

ll query(int x, int y, int i) {
    if (x <= tr[i].l && y >= tr[i].r) // 当前结点的区间完全被目标区间包含
        return tr[i].sum;
    else {
    	push_down(i, tr[i].r - tr[i].l + 1);
        int mid = (tr[i].l + tr[i].r) >> 1;
        if (x > mid)
            return query(x, y, i<<1|1);
        else if (y <= mid)
            return query(x, y, i<<1);
        else 
            return query(x, y, i<<1) + query(x, y, i<<1|1);
    }
}

int main() {
    scanf("%d", &n);
    scanf("%d", &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &data[i]);
    build(1, n, 1);

    while (m--) {
        int op, a, b, c;
        scanf("%d", &op);
        if (op == 1) { // 单点修改
            scanf("%d%d%d", &a, &b, &c);
            update(a, b, c, 1);
        }
        else { // 区间求和
            scanf("%d%d", &a, &b);
            printf("%lld\n", query(a, b, 1));
        }
    }

    return 0;
}
posted @ 2018-02-28 10:55  greyqz  阅读(146)  评论(0编辑  收藏  举报