資料結構-樹狀陣列(二)
阿新 • • 發佈:2018-11-14
複習筆記-樹狀陣列(二)
樹狀陣列(一)
略微進階的操作
在樹狀陣列(一)中,身為打線段樹要耗費好長時間(其實都不一定能揹著打出來)的蒟蒻,我安利了一波樹狀陣列,並且介紹了區間查詢和單點修改的基本操作。那麼,對基礎的樹狀陣列進行一些修改,結合差分,就可以同時進行區間修改和單點查詢。
差分陣列
儲存方式
差分陣列是相較於字首和的一種截然相反的儲存方式,字首和的每個數表示原陣列的字首和,而差分陣列的每個數表示原陣列這個數和上一個數的差,也就是說
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)完成區間查詢,這就是我說這兩者相反的第二個原因
差分陣列與樹狀陣列的結合
上面我叭叭了半天差分陣列不是瞎叭叭,而是要與樹狀陣列進行結合。
差分陣列與樹狀陣列特點對比:
————————————————————————————
差分陣列:字首和表示原數,可以用兩次單點修改完成區間修改
樹狀陣列:可以快速進行單點修改和查詢字首和
————————————————————————————
對比以上,不難想到,如果對差分陣列建立樹狀陣列,就可以對差分陣列進行字首和查詢達到單點查詢的目的,運用兩次單點修改來完成區間修改的目的
例題與程式實現
這道模板題要求完成區間修改和單點查詢
那麼利用差分陣列與樹狀陣列的結合,就可以這樣完成
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 }