upd: 本篇有了乙個更通(hui)俗(se)易(nan)懂的講解, 大家可以移步這裡圍觀~(使用了latex推柿子, 帶給你不一樣的清新體驗~
ok,以上兩期稍稍講了一下樹狀陣列的基本功能。。
當然,把樹狀陣列拉出來不能只有這兩個功能對不對。。。(不然網上都有怎麼把你們忽悠來看嘛)
樹狀陣列還是有兩把刷子的
(非戰鬥人員退散)
今天,我們要講的是:
區間加,區間查
什麼???
許多學過線段樹的人該詫異了吧。。
樹狀陣列還能幹這事?
答案是可以的。。
(○| ̄|_在此%拜一下發明這種做法的神犇orz)
還記得上次我們的c變化成了差分陣列嗎?
樹狀陣列就是擅長求字首和和維護差分資訊~
當然,這次的目標中有兩個區間字樣,所以要開兩個陣列(什麼邏輯嘛……)
其實原因並不是這樣。
我們用乙個差分陣列來儲存相鄰兩個資料的差,這個陣列命名為c1
此時,無論我們在樹狀陣列上怎麼亂搞,原資料的第i個點最後的值(記為a[i]吧)就是求一下c1[i]的總和
(嗯我們上一期的單點查)
對於區間修改,我們採取讓c1[l]加和讓c1[r+1]減的方式(還是差分)
對於區間查詢,我們有ans=sum[r]-sum[l-1](how old are you,差分?)
於是很明顯,最後原陣列中第i個點亂搞一波後的值是sigma(c1[j]) (j=1..i)
你們理清楚沒有。。
理清楚之後,
求1~i的和的時候,仔細看下面:
sum(i)=a[1]+a[2]+...+a[i]
=c1[1]+(c1[1]+c1[2])+...+(c1[1]+c1[2]+...+c1[i])
=i*c1[1]+(i-1)*c1[2]+...+1*c1[i]
=i*(c1[1]+c1[2]+...+c1[i])-(0*c1[1]+1*c1[2]+...+(i-1)*c1[i])
=i*sigma(c1[j])-sigma(c1[j]*(j-1)) (j=1..i)
所以,我們只要同時 維護一下sigma(c1[j])和sigma(c1[j]*(j-1))就行了。。
還記得c1的差分性質麼
所以我們再用乙個陣列c2搞出sigma(c1[j]*(j-1)),在維護c1的時候順手維護一下即可。。
這樣複雜度也不會被改變!!!非常好而且奇妙的性質。。。
sum[i]就照著上面的式子搞就行。。
下面,終於到了**,我有一件事情要說:其實只看**就好,上面講的沒啥用233
**的例子是用的luogu3372的【模板】線段樹 1 (哈哈哈哈,用線段樹的人們!)
題目傳送門:
裡面的資料是要用long long的。。
你們自己看情況改就好了233
而且聽說codevs1082的線段樹練習3也可以用這種方法水過。。
這題的傳送門:
而且碼長空間時間都要優於線段樹哦。。
不過main函式我就不寫了_ (:з」∠) _
而且這兩個題都要開long long而**裡是沒有開的
#include
#define gc getchar
int getnum()
class binary_tree3
int getnum()
public:
void build(int sum)
}void add(int *r, int x, int i)
int ask(int *r, int x)
void adda(int l, int r, int i)
int query(int l, int r)
};
大概就是這個樣子了。。
- 區間加的話就呼叫adda(l,r,i)就是區間[l,r]加i
- 區間查的話就輸出query(l,r)就是區間[l,r]的區間和了。。
對就是這樣。
模板篇 樹狀陣列們(四)
這是第四篇樹狀陣列了。我們之前講過樹狀陣列的以下幾大作用 單點加區間查 不會的話 區間加單點查 不會的話 區間加區間查 不會的話 然而上面的會不會的無所謂啊。因為上面我們查的都是區間和性質的東西。就是用字首和差分能減出來的東西 而我們今天要做的,是 單點修改,區間查詢最大值 在這裡,我要給大家講一下...
模板篇 樹狀陣列們(四)
這是第四篇樹狀陣列了。我們之前講過樹狀陣列的以下幾大作用 單點加區間查 不會的話 區間加單點查 不會的話 區間加區間查 不會的話 然而上面的會不會的無所謂啊。因為上面我們查的都是區間和性質的東西。就是用字首和差分能減出來的東西 而我們今天要做的,是 單點修改,區間查詢最大值 在這裡,我要給大家講一下...
模板篇 樹狀陣列們(一)
以下文章邏輯混亂,請確保精神正常後再 為什麼要搞樹狀陣列?快。lowbit是什麼呢?lowbit i 指的是i在二進位制表示下最低位的1及其後的所有0組成的值 比如36 在二進位制下是100100,最低位的1我加粗了,代表了4,所以lowbit 36 就是4。從圖上可以看出,對於樹狀陣列上的節點,第...