樹狀陣列 小白篇(2)暨區間修改

2021-08-22 12:18:26 字數 1849 閱讀 7701

這篇主要來講一講樹狀陣列的區間修改

因為乙個乙個點改,毫無疑問耗時太長

所以,機智的人類yy出了用差分來表示陣列

為了便於理解,簡單一點陣列:a[1]=0, a[2]=0, a[3]=0, a[4]=0, a[5]=0, a[6]=0 ,a[7]=0, a[8]=0, a[9]=0

用差分思想,delta[x]表示a[x]-a[x-1]

顯然,一開始delta=0

我們先計算出前n項和來

然後別眨眼,下面就是見證奇蹟的時刻!

有個分界線顯得正式一點

我們要把a[3]到a[6]整段提高3個單位長度,就讓delta[3]+=3, delta[7]-=3

想象成階梯,一端抬起,另一端就壓下去。(自行腦補)

那麼現在的a[x]+=delta[1]+delta[2]+……+delta[x-1]+delta[x]

我現在要得到前7項的和,s[7]+=每一項應該加的差分

暨s[7]+=(delta[1])+(delta[1]+delta[2])+(delta[1])+delta[2]+delta[3])+……+(delta[1]+delta[2]+delta[3]+delta[4]+delta[5]+delta[6]+delta[7])

我還是畫個圖吧(為了方便說明只畫差分的)

顯然搬過磚的都知道,這個磚不好搬,因為它不方

那我們就把它變方來

(為什麼那麼醜,因為我不會畫畫以及懶)

額妹子!現在就好表示這堆磚了!!!!!!!!!

(7+1)(∑delta【1~7】)-(delta*1+delta*2+……+delta*7)          (注意是7+1,不是7!!!!!!!!!)

後面的delta【n】*n很難看是不是?

那就表示成deltai【】

定義deltai【i】=delta【i】*i

顯然因為要大量求和,所以我們把deltai和delta維護成樹狀陣列

那麼

1 // 修改:把[l, r]區間均加上x     

2 update(delta, l, x);

3 update(delta, r+1, -x);

4 update(deltai, l, x * l);

5 update(deltai, r+1, -x * (r+1));

// 查詢:[l, r]區間和     

long long suml = s[l - 1] + l * query(delta, l - 1) - query(deltai, l - 1);

long long sumr = s[r] + (r + 1) * query(delta, r) - query(deltai, r);

ans=sumr - suml;

是不是很神奇?

#include#include#include#include#define lowbit(i) (i&-i)

typedef long long ll;

using namespace std;

const int n = 500005;

int n,m;

ll sum[n];

ll delta[n],deltai[n];

ll query(ll *p,int pos)

return ans;

}void updata(ll *p,int pos,int x)

}int main()

else

}return 0;

}

感謝

「每天心塞一點點」的部落格(我喜歡這個名字)

樹狀陣列 高階篇 區間修改,區間查詢

單點更新,區間查詢 我們知道,樹狀陣列最基本的功能是 單點更新,區間查詢 如下 int lowbit int x void add int x,int val int ask int x return res 區間更新,單點查詢 通過 單點更新,區間查詢 功能 差分的思想,我們實現了 區間更新,單點...

樹狀陣列區間修改

有時,我們要支援區間修改,區間查詢。線段樹可以做到。但是樹狀陣列更好寫。1d的情況 設 b i a i a i 1 則 a i b 1 b i a 1 a l b 1 b 1 b 2 b 1 b l a 1 a l l b 1 l 1 b 2 b l sum l i 1 b i 如果我們維護 b i...

樹狀陣列 小白篇(1)

身為一名弱省oier中的mengbier,簡單講一下我是怎麼學會基礎的樹狀陣列的 不算華麗的分割線 主要用於查詢任意一段資料中的所有元素之和。經過簡單修改可以在log n 的複雜度下進行範圍修改。也就是說你通過一系列神奇的操作可以實現在乙個數列中,修改其中一項ax的值 還可以是一段 並求出前n項和 ...