1. 程式人生 > >樹狀陣列 區間修改 區間查詢 講解

樹狀陣列 區間修改 區間查詢 講解

原來的值存在a[]裡面,多建立個數組c1[],注意:c1[i]=a[i]-a[i-1]。

那麼求a[i]的值的時候:

a[i]=a[i-1]+c1[i]=a[i-2]+c1[i]+c1[i-1]=…..=c1[1]+c1[2]+…+c1[i]。

我們叫c1[]陣列為差分陣列。

這樣之後,a[i]就可以用差分陣列的區間和來表示。之後我們就不需要原陣列a[i]了,只需要維護c1[i]就可以。

這樣我們區間修改時,對於差分陣列來說隻影響端點處的值。也就是對於[l,r]增量k時,只需要讓c1[l]+=k,c1[r+1]-=k即可。

#include<bits/stdc++.h> using namespace std; #include<cstring> #define lowbit(x) (x&-x) int const maxn=1e5+10; int c[maxn];//樹 int n; int sum(int i){     int s=0;     while(i>0){         s+=c[i];         i-=lowbit(i);     }     return s; } void add(int i,int val){     while(i<=n){         c[i]+=val;         i+=lowbit(i);     } } int main(){     int x;     cin>>n;     for(int i=1;i<=n;i++){         scanf("%d",&x);         add(i,x);         add(i+1,-x);     }     int l,r,q;     cin>>q;     for(int i=1;i<=q;i++){         cin>>x;         cout<<sum(x)<<endl;     } }

區間查詢:

我們用sum(1,k)表示區間1到k的和。

那麼

sum(1,k)   =   c1(1)+

                      c1(1)+c1(2)+

                      c1(1)+c1(2)+c1(3)+

                      …+

                      c1(1)+c1(2)+…+c1(k)。

                  =  k*c1(1) + (k-1)*c1(2) + ... +1 * c1(k)

                  =  k*( c1[1] + c1[2] +...+c1[k]  )  - ( 0*c1[1] + 1 *c1[2] + ... +(k-1) * c1[k] )

                  =  k*sum(c1,k) - ( 0*c1[1] + 1 *c1[2] + ... +(k-1) * c1[k] )

減號後面的需要額外維護c2陣列:c2[i]=(i-1)*c2[i] 然後每次求字首和即可。

區間查詢:

#include<bits/stdc++.h> using namespace std; #include<cstring> #define lowbit(x) (x&-x) int const maxn=1e5+10; int c[maxn],c2[maxn];//樹 int n; int sum(int c[],int i){     int s=0;     while(i>0){         s+=c[i];         i-=lowbit(i);     }     return s; } void _add2(int c[],int i,int val){     while(i<=n){         c[i]+=val;         i+=lowbit(i);     } } void add(int c[],int i,int val){     _add2(c2,i,val*(i-1));     while(i<=n){         c[i]+=val;         i+=lowbit(i);     }     } int sum2(int r){     return r*sum(c,r) - sum(c2,r); } int main(){ //    freopen("r.txt","r",stdin);     int x;     cin>>n;     int l,r,q;     for(int i=1;i<=n;i++){         scanf("%d%d%d",&l,&r,&x);         add(c,l,x);         add(c,r+1,-x);     }          cin>>q;     for(int i=1;i<=q;i++){         cin>>l>>r;         cout<<sum2(r)-sum2(l-1)<<endl;     }      }