板子1
板子2在放板子的**之前,先講一下樹狀陣列。
樹狀陣列的作用:
在有修改時可以做到log級別求字首和
還可以結合差分等神奇的東西食用
空間比線段樹要省的多,**量也少的多
在單點查詢的時候比線段樹快了不是一點(我真的沒有拿線段樹的板子去拍這兩個題)
我們先來看一下樹狀陣列是個什麼東西
首先,我們有乙個序列a,其次lowbit(x)表示x的二進位制表示中,最低位的1和後面的0構成的數。
樹狀陣列c[i]記錄序列a的區間[i-lowbit(i)+1,x]中所有數的和。
why?我們畫一畫樹狀陣列
它是不是很像一棵樹
同時我們可以發現一些性質:
每個c[x]儲存了以它為根的子樹中葉節點的和
c[x]的子節點數=lowbit(x)
c[x]的父親是c[x+lowbit(x)]
樹深度為logn
占用空間:o(n)
lowbit好像很重要的樣子,so,lowbit怎麼求呢
lowbit(x)=x&(~x+1)=x&-x,因為~x+1=-x。
why?
舉個例子(設x>0,這裡牽扯到樹狀陣列不能處理下標為0的情況)
樹狀陣列支援兩種神奇的修改與查詢。
一.單點修改,區間查詢(板子1)
二.區間修改,單點查詢(板子2)
先說一說第一種
前面提到過c[x]的父親是c[x+lowbit(x)],所以更改的**就是這樣:
void update(int x,int因為c陣列是維護的字首和,所以當查詢區間[l,r]的時候,我們可以算出sum(r)-sum(l-1),這裡sum(i)是[1,i]的和。v)
怎麼算sum(i)?
因為c[x]記錄的是[lowbit(x)+1,x]這個區間的和,為了統計[1,x],所以我們每次x要減去lowbit(x)。
**
int sum(int再來說一說第二種神奇的操作(區間修改,單點查詢)我真的沒有拿線段樹的板子做這道題x)
我們先看乙個東西:差分
現在有乙個a陣列:a[1],a[2]……a[n]
還有乙個b陣列:b[1]=a[1]-a[0],b[2]=a[2]-a[1]……b[i]=a[i]-a[i-1]
b陣列就叫做差分陣列。
通過差分陣列的定義,我們知道:a[2]=a[1]+b[2]=b[1]+b[2],a[3]=a[2]+b[3]=b[1]+b[2]+b[3]……
我們發現了差分的乙個性質:a[i]=b[1]+b[2]+……+b[i]
那差分有什麼用呢?
我們想到這裡是區間修改,如果把區間中的每乙個點當做單點修改,複雜度o(nlogn),好像還不如暴力,而且樹狀陣列也木有懶標記之類的操作,這時就要用到差分陣列了。
若我們讓[l,r]這個區間每個數都加上k,則對於差分陣列來說,會變的只有b[l],b[r+1]。因為a[l]加了k,而a[l-1]不變,所以b[l]增加了k,a[r]增加了k,a[r+1]不變,所以b[r+1]減少k。
當單點查詢時,就是詢問字首和(也就是上面差分的性質)
so,我們只是把樹狀陣列維護的物件從a陣列變成了它的差分陣列b陣列而已,其他的不變。
這裡放上板子
#include//這個是板子2,板子1也差不多
using
namespace
std;
int n,m,c[5000009],a[500009
];int
read()
while(ch>='
0'&&ch<='9'
)
return f?-x:x;
}void update(int x,int
v)int sum(int
x)int
main()
else
printf(
"%d\n
",sum(x));}}
板子 樹狀陣列
已知乙個數列,你需要進行下面兩種操作 1.將某區間每乙個數數加上x 2.求出某區間數值和 第一行包含兩個整數n m,分別表示該數列數字的個數和操作的總個數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含2或4個整數,表示乙個操作,具體如下 操作1 格式 1 ...
字尾陣列板子
sa i j表示為按照從小到大排名為i的字尾 是以j 下標 開頭的字尾 rank i j 表示為按照從小到大排名 以i為下標開始的字尾 排名為j height陣列 定義height i suffix sa i 1 和suffix sa i 的最長公共字首 include include includ...
c 陣列大數板子
int compare const char a,int len1,const char b,int len2 while i 0 while j 0 if jin s k jin 0 for int j 0 j k 2 j swap s j s k j 1 s k 0 複雜度 o n 複雜度o n...