POJ 3468: A Simple Problem with Integers

題目在此ui

解題思路:還是典型的線段樹應用,只不過增長了更新值部分的代碼。須要注意的是,操做時要「按需」更新,不要每次都更新到葉子節點,否則就失去了使用線段樹的意義。code

對於本題,能夠在樹節點中設置一個 delta 變量,僅當須要向下更新時,纔將 delta 變量的值傳下去,不然只改動當前節點的 delta 便可,從而起到「緩衝」的做用。get

代碼:cmd

#include <cstdio>

#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 (scanf("%d%d", &N, &Q) != EOF) {
        for (int i = 1; i <= N; ++i) {
            scanf("%d", &numbers[i]);
        }

        build(1, 1, N);

        char cmd;
        int l, r;
        long long v;
        while (Q--) {
            scanf(" %c", &cmd);
            scanf("%d%d", &l, &r);
            switch (cmd) {
            case 'Q':
                printf("%lld\n", query(1, l, r));
                break;

            case 'C':
                scanf("%lld", &v);
                if (v) {
                    update(1, l, r, v);
                }
                break;
            }
        }
    }

    return 0;
}
相關文章
相關標籤/搜索