樹狀陣列的那啥啥啥

2022-03-29 15:10:33 字數 4366 閱讀 5224

emmmmm, 在我們學習樹狀陣列之前, 我們應該知道lowbit(n)運算, lowbit(n)定義為非負整數n在二進位制下「最低位的1及後面所有的0」構成的數值, 例如n = 10的二進位制表示為\((1010)_2\),則\(lowbit(n) = 2 = (10)_2\), 顯然可知

\[lowbit(n) = n \and (\sim n +1) = n \and (-n)

\]那就先寫一道lowbit的例題吧:

一天,cc買了n個容量可以認為是無限大的瓶子,開始時每個瓶子裡有1公升水。接著~~cc發現瓶子實在太多了,於是他決定保留不超過k個瓶子。每次他選擇兩個當前含水量相同的瓶子,把乙個瓶子的水全部倒進另乙個裡,然後把空瓶丟棄。(不能丟棄有水的瓶子)

顯然在某些情況下cc無法達到目標,比如n=3,k=1。此時cc會重新買一些新的瓶子(新瓶子容量無限,開始時有1公升水),以到達目標。

現在cc想知道,最少需要買多少新瓶子才能達到目標呢?

一行兩個正整數, $ n,k(1\le n\le 2\times 10^9,k\le 10001≤n≤2×10

9 ,k≤1000)$

乙個非負整數,表示最少需要買多少新瓶子。

不難看出, 我們盡量把最小的兩個瓶子給合併, 所以我們用lowbit將n分成二的整次冪, 再全都丟到乙個優先佇列中, 每次取出最小的兩個數進行合併, 直到滿足條件為止。

#include using namespace std;

typedef long long ll;

const int inf = 0x3f3f3f3f;

const int maxn = 5e5 + 100;

const int maxm = 3e3 + 10;

const double eps = 1e-5;

template < typename t > inline void read(t &x)

while(isdigit(ch))

x *= ff;

}template < typename t > inline void write(t x)

if(x < 0) putchar('-'), x = -x;

static t tot = 0, ch[20];

while(x)

while(tot) putchar(ch[tot--]);

}int n, k, ans, sum;

priority_queue < int > q;

inline int lowbit(int x)

int main()

while(sum > k)

// printf("ans = %d\n", ans);

write(ans);

return 0;

}

知道了lowbit的用法, 所以我們把乙個序列分成\(log(x)\)小區間,

while(x > 0)
樹狀陣列就是基於上述思想的資料結構, 其基本用途是維護序列的字首和。對於給定的序列a, 我們建立乙個陣列c, 其中c[x]儲存序列a的區間[x - lowbit(x) + 1, x]中所有數的和, 及\(\sum^x_a[i]\)

那我們就看樹狀陣列最基本的操作吧

如題,已知乙個數列,你需要進行下面兩種操作:

1.將某乙個數加上x

2.求出某區間每乙個數的和

第一行包含兩個整數n、m,分別表示該數列數字的個數和操作的總個數。

第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。

接下來m行每行包含3個整數,表示乙個操作,具體如下:

操作1: 格式:1 x k 含義:將第x個數加上k

操作2: 格式:2 x y 含義:輸出區間[x,y]內每個數的和

輸出包含若干行整數,即為所有操作2的結果。

對於查詢1~x的字首和, 我們按照剛才提出的方法, 應該求出x二進位制表示中每個等於1的位, 把[1, x]分成\(log(n)\)個小區間, 而每個小區間和都已經儲存在陣列c中。所以把上邊的**稍加改寫即可在\(log(n)\)的時間內查詢字首和:

inlnie int ask(int x)
當然, 若要查詢區間[l, r]中所有數的和, 只需要計算\(ask(r)-ask(l - 1)\)

對於單點修改, 乙個數的改變會影響c[x]即其所有祖先節點儲存的"區間和"包括a[x],而任意乙個節點的祖先最多有\(log(n)\)個, 我們逐一對它們的c值更新即可。

inline void add(int x, int k)
在執行所有操作之前, 我們需要對樹狀陣列進行初始化--針對原始序列a構造乙個樹狀陣列

為了簡便, 我們一邊初始的方法是, 每讀入乙個a[i], 執行add(i, a[i])的操作, 時間複雜度是\(o(nlogn)\), 通常這種方法已經足夠。

還有一種更高效的方法, 用字首和的方式直接更新c[x], 時間複雜度為\(o(n)\), 不過用這種方法需要多開乙個字首和陣列

for(int i = 1; i <= n; ++i)
for(int i = 1; i <= n; ++i) 

for(int i = 1; i <= n; ++i)

如題,已知乙個數列,你需要進行下面兩種操作:

1.將某區間每乙個數數加上x

2.求出某乙個數的值

第一行包含兩個整數n、m,分別表示該數列數字的個數和操作的總個數。

第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。

接下來m行每行包含2或4個整數,表示乙個操作,具體如下:

操作1: 格式:1 x y k 含義:將區間[x,y]內每個數加上k

操作2: 格式:2 x 含義:輸出第x個數的值

輸出包含若干行整數,即為所有操作2的結果。

對於區間修改, 我們可以通過查分而轉換成單點修改, 此時的c[i]陣列就是區間[x - (x & -x) + 1, x], 所有差分數列的和, 所以更改後的a[i]的值就等於a[i] + c[i]的字首和

inline void add(int x, int k) 

inline int ask(int x)

cout << a[i] += ask(i);

這個名字就當沒看見吧。。。我也就不想打了, 直接粘學長的部落格吧。

學長部落格

這道題啊,超級厲害啊,各種坑挖的,什麼無符號 longlong,什麼座標為0。

首先,你需要宣告乙個 unsigned long long 才不會被爆掉,然後記得每個座標都加上乙個1,因為資料裡面是有位0的,而樹狀陣列裡面是不能為零的,不然會無線迴圈,lowbit(0)=0 然後就不停地加或者減無法退出。

因為題目上讓樹神留下來5個mm,所以我們就可以開五個樹狀陣列來記錄下來元素能嚴格遞增並且長度達到第i個樹狀陣列的方案數,更新的步驟是這樣的,將第i個數加入第乙個樹狀陣列裡面,統計小於第i個數的個數,如果然後加到下乙個樹狀陣列裡面這樣每次迴圈4次。

最後輸出第五個樹狀陣列所有元素之和就好了。

其實可以把樹狀陣列壓成二維(只是形式上的), 修改和查詢方法還是和一維相同, 二維樹狀陣列就是別的寫法了。

#include using namespace std;

typedef unsigned long long ull;

const int inf = 0x3f3f3f3f;

const int maxn = 1e6 + 100;

const int maxm = 3e3 + 10;

const double eps = 1e-5;

template < typename t > inline void read(t &x)

while(isdigit(ch))

x *= ff;

}template < typename t > inline void write(t x)

if(x < 0) putchar('-'), x = -x;

static t tot = 0, ch[20];

while(x)

while(tot) putchar(ch[tot--]);

}ull n, maxx, a[maxn], c[6][maxn];

inline void add(ull num, ull x, ull v)

}inline ull ask(ull num, ull x)

int main()

for(ull i = 1; i <= n; ++i)

} write(ask(5, maxx));

return 0;

}

轉int啥啥啥的

1 string轉int型別的話。需要用double.valueof 這寫string型別的資料 intvalue 2 保留小數點 float scale float 100 decimalformat fnum new decimalformat 0.00 string dd fnum.forma...

啥 啥 啥,服務治理是個啥

首先,先說下服務治理的邊界,本質上任何能提公升服務可用性,效能,讓服務更穩定等等,只要是能讓服務執行的更好,都屬於服務治理的範疇。服務治理比較常見的話題 服務發現,服務變更管理,服務監控,服務擴容縮容,服務自我保護,服務降級,服務授權防攻擊,服務上線驗證和灰度發布,服務問題定位和跟蹤,服務負載,服務...

想到啥寫啥

真的太久沒寫過部落格了。自從msn的blog關掉以後就就沒怎麼正經寫過 好像之後還寫過一編年終總結 就得blog沒了,搬遷到sina之後在公司有不好登入,趁今天生病在家修養,稍微記錄一下流水漲。最近一段時間得到了公司支援,推行了一段不太完整的 敏捷開發 不完整,是因為只有開發在做,並沒有推行到測試 ...