1. 程式人生 > >資料結構8-差分陣列

資料結構8-差分陣列

做到了這個題,傳送門
一眼看完就知道是線段樹,,,,
但是,,我還是看了題解、、、
線段樹會TLE一個點。。。
怎麼辦呢
注意到,,這道題因為修改和查詢是分開的,所以線段樹有點浪費。
這道題實際上是一個差分陣列

在網上講差分陣列的博文很少,也很難找到。一度以為差分陣列是傳播於小眾的神犇技巧所以一直放著沒有去研習。今天做了bzoj1635後發現各路神犇都用差分陣列,本蒟卻傻傻寫了線段樹。。。。。
對於序列a{},取a[i]-a[i-1]為其差分陣列b[i]的值,可以發現,a[i]=∑bj(1≤j≤i)
如 對於序列 a、b、c、d 其差分陣列為 a、 b-a、 c-b、 d-c
(a-0)
有a=a,b=a+(b-a),c=a+(b-a)+(c-b),d=a+(b-a)+(c-b)+(d-c)
那麼,如果我們進行區間加減操作,且修改的區間連續不相交,那麼,若將(x,y)區間整體加val,我們就可以對差分陣列的b[x]加val,b[y+1]減val。此時差分陣列所對應的原序列即為(x,y)整體加val後的區間。
如此而已,推一推就明白了。

其實就是記錄陣列的第 i位與i-1位的差值,這樣更新區間的時候只需要對於頭尾進行更新就可以了
給出程式碼

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 100000 + 10;
int m, q;
long long a[N], d[N], sum[N];
int main() {
    int n;
    while (scanf("%d", &n) && n) {
        memset(a, 0, sizeof(a));//初始化都為0
        int l, r;
        memset(d, 0, sizeof(d));
        d[1] = a[1];//特殊處理第一個數
        for (int i = 0; i < n; i++) {
            scanf("%d%d", &l, &r);
            d[l] += 1;
            d[r+1] -= 1;
        }
        memset(sum, 0, sizeof(sum));
        for (int i = 1; i <= n; ++i) {
            sum[i] = sum[i-1] + d[i]; //求d[i]字首和, 也就是修改後的a[i]
        }
        for (int i = 1; i <= n; ++i){
            printf("%lld",sum[i]);
            if(i != n) printf(" ");
        }
        puts("");
    }

    return 0;
}