AcWing 242. 一個簡單的整數問題(樹狀陣列解法)

Alphacoo發表於2020-11-13

AcWing 242. 一個簡單的整數問題

題意

給定長度為N的數列A,然後輸入M行操作指令。
第一類指令形如“C l r d”,表示把數列中第l~r個數都加d。
第二類指令形如“Q X”,表示詢問數列中第x個數的值。
對於每個詢問,輸出一個整數表示答案。

分析

如果這題不是使用線段樹,而是使用樹狀陣列來解決,怎麼做呢?怎麼思考呢?

樹狀陣列僅支援單點修改和區間查詢,但這題是要求區間修改和單點查詢,好像跟樹狀陣列反著來的。。。

仔細觀察一下,其實把A[l]到A[r]都加d,就是把l到r這個區間中的數都加d, r+1到n這個區間中的數都減d,因此可以使用一個額外陣列B來維護區間的變化, 至於查詢第x個數,就是A[x]+ B[1]~B[x]

注意

這題序列元素的範圍是10億,因此有些變數需要使用long long

程式碼

#include <iostream>
#include <cstring>
#define ll long long

using namespace std;

const int N = 1e5 + 5;

//a為儲存資料的陣列,b為樹狀陣列
ll a[N];
int b[N];
//n為序列長度,m為操作指令次數
int n, m;

//lowbit操作
int lowbit(int x) {
    return x & -x;
}

//區間查詢
ll sum(int x) {
    ll ans = 0;
    while (x) {
        ans += b[x];
        x -= lowbit(x);
    }
    return ans;
}

//單點修改
void add(int x, int v) {
    while (x <= n) {
        b[x] += v;
        x += lowbit(x);
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);//輸入序列
    while (m--) {
        char op[2];
        scanf("%s", op);
        if (op[0] == 'C') {
            int l, r, d;
            scanf("%d%d%d", &l, &r, &d);
            //b[l]加d,相當於a[l]~a[n]都加d
            add(l, d);   
            //b[r + 1]減d,相當於a[r + 1]~a[n]都減d
            add(r + 1, -d);
        } else {
            int x;
            scanf("%d", &x);
            printf("%lld\n", a[x] + sum(x));
        }
    }
}

相關文章