1. 程式人生 > >資料結構-樹狀陣列(二)

資料結構-樹狀陣列(二)

複習筆記-樹狀陣列(二)

樹狀陣列(一)

略微進階的操作

在樹狀陣列(一)中,身為打線段樹要耗費好長時間(其實都不一定能揹著打出來)的蒟蒻,我安利了一波樹狀陣列,並且介紹了區間查詢和單點修改的基本操作。那麼,對基礎的樹狀陣列進行一些修改,結合差分,就可以同時進行區間修改和單點查詢。

差分陣列

儲存方式

差分陣列是相較於字首和的一種截然相反的儲存方式,字首和的每個數表示原陣列的字首和,而差分陣列的每個數表示原陣列這個數和上一個數的差,也就是說

C1=A1

Cx=Ax-Ax-1

那麼容易推出

C1+C2+...+Cm=Am

也就是說,差分陣列元素的字首和等於原陣列該元素的值,這就是我說它與字首和截然相反的第一個原因。

優勢

差分陣列由於每個數存的是與上一個數的差,可以理解成存的是資料的波動。那麼,需要區間修改時,也就相當於區間內波動不變,區間左端波動上升,區間右端波動下降。這樣就可以用O(1)複雜度完成區間修改。也就是說

如果把第x到第y加上k,只需要把差分陣列第x個元素+k,第y+1個元素-k,就相當於完成了區間修改,只需要修改兩處。

這是差分陣列的修改的基礎程式碼

1 void add(int x,int y,int k){
2     c[x] += k;
3     c[y + 1] -= k;
4 }

綜上,差分陣列可以O(1)完成區間修改。由於字首和可以O(1)完成區間查詢,這就是我說這兩者相反的第二個原因

差分陣列與樹狀陣列的結合

上面我叭叭了半天差分陣列不是瞎叭叭,而是要與樹狀陣列進行結合。

差分陣列與樹狀陣列特點對比:

————————————————————————————

差分陣列:字首和表示原數,可以用兩次單點修改完成區間修改

樹狀陣列:可以快速進行單點修改和查詢字首和

————————————————————————————

對比以上,不難想到,如果對差分陣列建立樹狀陣列,就可以對差分陣列進行字首和查詢達到單點查詢的目的,運用兩次單點修改來完成區間修改的目的

例題與程式實現

P3368

這道模板題要求完成區間修改和單點查詢

那麼利用差分陣列與樹狀陣列的結合,就可以這樣完成

 1     #include<bits/stdc++.h>
 2     using namespace std;
 3     int n,m,l,r,x;
 4     long long c[500010],k,a;
 5     int lowbit(int x){
 6         return x&(-x);
 7     }
 8     void add(int x,long long y){
 9         while(x<=n){
10             c[x]+=y;
11             x+=lowbit(x);
12         }
13     }
14     long long sum(int x){
15         long long cnt=0;
16         while(x){
17             cnt+=c[x];
18             x-=lowbit(x);
19         }
20         return cnt; 
21     }
22     int main(){
23         scanf("%d%d",&n,&m);
24         long long now=0;
25         for(int i=1;i<=n;i++){
26             scanf("%lld",&a);
27             add(i,a-now);
28             now=a;
29         }
30         while(m--){
31             scanf("%d",&x);
32             if(x==1){
33                 scanf("%d%d%lld",&l,&r,&k);
34                 add(l,k);
35                 add(r+1,-k);
36             }
37             else{
38                 int s;
39                 scanf("%d",&s);
40                 printf("%lld\n",sum(s));
41             }
42         }
43         return 0;
44 }