1. 程式人生 > >【模板】樹狀數組上的差分數組

【模板】樹狀數組上的差分數組

string cstring 能夠 name 證明 spa data 形式 pre

數據差分化是一個很神仙也很實用的方法。

具體操作就是將一個數化為多個項的和的形式,這些我們產生的項多為g(x)=f(i)-f(i-1)一類形式,這樣可以錯位相消去,十分巧妙。

數據差分化有以下神仙之處:

  • 通過差分數據得到原數據g(x):十分顯然,g(x)=f(1)+f(2)+f(3)+……+f(x) , ( f(0)=0 )。證明略。

  • 改變區間[ l , r ]的值,只需要進行g(l)=g(l)+k, g(r+1)=g(r+1)-k這樣的操作就行了。原因是中間的項全部通過加減抵消了那個加入的k。

因此,維護一個差分化的數據,需要一種能夠高效訪問區間[ l , r ]的數據結構,那這種數據結構還有什麽呢?當然是

線段樹&樹狀數組

對不起我太弱了導致只知道這兩個

附上代碼(樹狀數組( 2 ) 的)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline ll qr(){
    char c=getchar();
    ll x=0,q=1;
    while(c<48||c>57)
        q=c==45?-1:q,c=getchar();
    while(c>=48&&c<=57)
        x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return q*x;
}
const int maxn=500000+15;
ll data[maxn];
#define lw(x) (x&(-x))
int n,m;
#define RP(t,a,b) for(int t=(a),edd=(b);t<=edd;t++)
inline void add(int pos,int dataq){
    int t=pos;
    while(t<=n){
        data[t]+=dataq;
        t+=lw(t);
    }
    return;
}
inline ll ask(int x){
    ll ret=0;
    int pos=x;
    while(pos){
        ret+=data[pos];
        pos-=lw(pos);
    }
    return ret;
}
int templ,last;
int t1,t2,t3,t4;
int main(){
    //freopen("in.in","r",stdin);
    //freopen("out.out","w",stdout);
    n=qr();
    m=qr();
    RP(t,1,n){
        templ=qr();
        add(t,templ-last);
        last=templ;
    }
    RP(t,1,m){
        t1=qr();
        if(t1==1){
            t2=qr();
            t3=qr();
            t4=qr();
            add(t2,t4);
            add(t3+1,-t4);
        }
        else{
            t2=qr();
            cout<<ask(t2)<<endl;
        }
    }
    return 0;
}

此類數據結構,應靈活應用,來達到一些神仙的十分之一的水平。

再次感嘆我真是太弱了

【模板】樹狀數組上的差分數組