淺談差分數組的原理及簡單應用

1、差分數組的定義及用途

1.定義:

對於已知有n個元素的離線數列d,咱們能夠創建記錄它每項與前一項差值的差分數組f:顯然,f[1]=d[1]-0=d[1];對於整數i∈[2,n],咱們讓f[i]=d[i]-d[i-1]。html

2.簡單性質:

(1)計算數列各項的值:觀察d[2]=f[1]+f[2]=d[1]+d[2]-d[1]=d[2]可知,數列第i項的值是能夠用差分數組的前i項的和計算的,即d[i]=f[i]的前綴和。
(2)計算數列每一項的前綴和:第i項的前綴和即爲數列前i項的和,那麼推導可知

便可用差分數組求出數列前綴和;ios

3.用途:

(1)快速處理區間加減操做:

假如如今對數列中區間[L,R]上的數加上x,咱們經過性質(1)知道,第一個受影響的差分數組中的元素爲f[L],即令f[L]+=x,那麼後面數列元素在計算過程當中都會加上x;最後一個受影響的差分數組中的元素爲f[R],因此令f[R+1]-=x,便可保證不會影響到R之後數列元素的計算。這樣咱們沒必要對區間內每個數進行處理,只需處理兩個差分後的數便可;數組

(2)詢問區間和問題:

由性質(2)咱們能夠計算出數列各項的前綴和數組sum各項的值;那麼顯然,區間[L,R]的和即爲ans=sum[R]-sum[L-1];數據結構

2、相關題目

1.[HDU1556]Color the ball

Description

-N個氣球排成一排,從左到右依次編號爲1,2,3....N.每次給定2個整數a b(a <= b),lele便爲騎上他的「小飛鴿"牌電動車從氣球a開始到氣球b依次給每一個氣球塗一次顏色。可是N次之後lele已經忘記了第I個氣球已經塗過幾回顏色了,你能幫他算出每一個氣球被塗過幾回顏色嗎?
-Input:每一個測試實例第一行爲一個整數N,(N <= 100000).接下來的N行,每行包括2個整數a b(1 <= a <= b <= N)。當N = 0,輸入結束。
-Output:每一個測試實例輸出一行,包括N個整數,第I個數表明第I個氣球總共被塗色的次數。測試

Solution

1.記錄各次操做,對差分數組進行對應修改,改變量爲1(用途1);
2.使用性質(1)計算各項的值便可;spa

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std; 
int d[100010],a[100010],l,r;
int main(){
    int n;
    while(scanf("%d",&n),n)
    {
        memset(d,0,sizeof(d));
        memset(a,0,sizeof(a));
        for(int i=1;i<=n;++i){
            scanf("%d%d",&l,&r);
            d[l]+=1;
            d[r+1]-=1;
        }
        for(int i=1;i<=n;++i) a[i]=a[i-1]+d[i];
        for(int i=1;i<n;++i) printf("%d ",a[i]);
        printf("%d\n",a[n]);
    }
    return 0;
}

2.[NKOJ3754]數列遊戲

Description

-給定一個長度爲N的序列,首先進行A次操做,每次操做在Li和Ri這個區間加上一個數Ci。
而後有B次詢問,每次詢問Li到Ri的區間和。
初始序列都爲0。
-輸入格式:
第一行三個整數N A B。(1<=N<=1000000,1<=A<=N,A<=B<=N)
接下來A行,每行三個數Li Ri Ci。(1<=Li<=N,Li<=Ri<=N,|Ci|<=100000000000000)。
接下來B行,每行兩個數 Li Ri。範圍同上。
-輸出格式:
對於每次詢問,輸出一行一個整數。
由於最後的結果可能很大,請對結果mod 1000000007。code

Solution

1.應用(1)處理區間加;
2.用性質(1)求出修改後數列,再求出相應數列和(應用2)或直接用性質(2)求解;
3.注意隨時取模;htm

#include<iostream>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<cstdio>
const long long mod=1000000007; 
using namespace std;
long long d[100010],f[100010],sum[100010];
int main(){
    int n,a,b;
    scanf("%d%d%d",&n,&a,&b);
    memset(d,0,sizeof(d));
    memset(f,0,sizeof(f));
    memset(sum,0,sizeof(sum));
    for(int i=1;i<=a;++i){
        long long l,r,c;
        scanf("%ld%ld%ld",&l,&r,&c);
        f[l]=(f[l]+c)%mod;
        f[r+1]=(f[r+1]-c)%mod;
    }
    for(int i=1;i<=n;++i)  d[i]=(d[i-1]+f[i])%mod;
    for(int i=1;i<=n;i++) sum[i]=(sum[i-1]+d[i])%mod;
    for(int i=1;i<=b;++i){
        int l,r;
        scanf("%d%d",&l,&r);
        printf("%ld\n",(sum[r]-sum[l-1])%mod);
        //printf("%ld\n",temp>=0?temp:temp+mod);//防止結果爲負; 
    }
    return 0;
}

3.[NOIP2012提升&洛谷P1083]借教室

題解隨筆:http://www.cnblogs.com/COLIN-LIGHTNING/p/8467795.html

4.[洛谷P3948]數據結構

題解隨筆:http://www.cnblogs.com/COLIN-LIGHTNING/p/8482463.html

相關文章
相關標籤/搜索