分塊 乙個奇怪的分塊演算法 B樹 分塊

2022-06-26 12:33:12 字數 3191 閱讀 4887

資料結構,支援以下兩種操作:

空間複雜度\(o(n^})\),預處理時間複雜度\(o(n^})\)。

其實這個東西的本質是將b樹留下來3層,然後葉子節點上跑暴力。

這裡實現了乙個支援\(o(1)\)區間改和\(o(n^2)\)單點查的資料結構。空間複雜度\(o(n^2)\)。

隨便維護一下這個區間內的\(\frac\)種區間的tag。修改的時候直接改對應區間,詢問的時候把包含詢問點的區間全都遍歷一遍。

**:

struct blo4

} void qu_min(int l, int r, int cn)

int query(int cn)

};

這裡實現了乙個支援\(o(1)\)區間改和\(o(n)\)單點查的資料結構。空間複雜度\(o(n^})\)。

具體就是分塊。分成\(\lceil\sqrt\rceil\)塊,然後再對每一塊記錄整塊的tag。我們發現此時有\(\lceil\sqrt\rceil+1\)塊,每塊長度為\(\lfloor\sqrt\rfloor\)。

我們對於每個塊用乙個blo4維護,然後再對tag開乙個blo4維護。

我們發現一次修改會覆蓋一段連續的整塊和兩邊的小塊的字首或者字尾。也就是變成了兩個小塊的blo4和乙個tag的blo4的區間改。

查詢的時候我們需要查詢這個點在小塊內的點值和覆蓋這個點的tag。這個就是兩次blo4的單點查。

**:(裡面維護了字首和字尾,這個之後解釋)

struct blo2

++alen; a[alen].build(tmp, 1, alen-1);

} void qu_min_suf(int l, int cn)

void qu_min_pre(int r, int cn)

void qu_min(int l, int r, int cn) }

int query(int cn)

};

這裡實現了乙個支援\(o(1)\)區間改和\(o(n^})\)單點查的資料結構。空間複雜度\(o(n^})\)。

就是類似blo2的弄一下,除了blo2中的維護開的是blo4,而現在我開的是blo2,其他完全相同。

你會發現這不就是b樹嗎?

**

struct blo1

++alen; a[alen].build(tmp, 1, alen-1);

} void qu_min(int l, int r, int cn) }

int query(int cn)

};

我們注意到這裡的\(o(1)\)快有乙個log了。事實上這裡的\(o(1)\)是跑不過zkw線段樹的。(在\(n=6250000\)下)

如果就照著我上文所說來維護,事情會變成\(o(1)\)在最壞情況下成為\(3\times 3=9\)次blo4的區間修改。很離譜。而且會訪問大量陣列。不太行。

怎麼辦,我們發現blo1改動blo2的時候實際上只有乙個是真正的區間改,還有兩個是前字尾改動。我們可以特殊維護一下前字尾。這樣雖然會導致回答的時候變慢(也沒有變慢多少),但是顯著提公升了演算法速度。

進一步,我們發現blo4太雞肋了,我們可以將其維護進blo2當中(就不用跳來跳去了),這樣子就更快了一點。

這份**為了解決輸入過大的問題,在**中根據輸入的隨機種子生成詢問。

#include#define ll long long

#define maxn 6250100

#define maxsqr1 6250100

#define maxsqr2 2510

#define maxsqr4 50

#define inf 1010000000

using namespace std;

templatevoid read(t &cn)

else

}templatevoid write(t cn)

while(cn) wei++, cm = cm*10+cn%10, cn = cn/10;

while(wei--) putchar(cm%10+48), cm = cm/10;

putchar(cx+48);

}templatevoid writes(t cn)

templatevoid writel(t cn)

namespace getnum

unsigned get_r(unsigned cn)

int get_n(int l, int r)

void get_val(int &val)

void get_ne(int &typ, int &pos, int &l, int &r, int &val) }

templateinline void max(t &cn, t cm)

templateinline void min(t &cn, t cm)

struct blo2

i = j+1;

} ++alen;

for(int i = 1;i<=alen-1;i++) for(int j = i;j<=alen-1;j++) b[i][j] = inf;

} void qu_min(int l, int r, int cn) }

int query(int cn) };

struct blo1

++alen; a[alen].build(tmp, 1, alen-1);

} void qu_min(int l, int r, int cn) }

int query(int cn) };

blo1 t;

int n, q1, q2, seed, a;

int a[maxn+1];

int main()

\)的數量級,這個演算法才會和zkw的實際效率有顯著差異(意為無論如何實現都能與zkw較好的實現有相近的效率,並且較好的實現可以做到使用時間為zkw的一半以內)。但是那時他將使用4gb的空間,有點離譜。

我們可以開乙個k叉樹,取\(k=n^}\),我們就將一次修改變成了1次長度為\(n^}\)的陣列上的區間改和4個長度為\(n^}\)個陣列上的字首字尾改。這個東西我們可以用修改\(o(1)\),查詢\(o(n)\)的st表來實現,複雜度為修改\(o(1)\),查詢\(o(n^}\log n)\),空間\(o(n\log n)\)。

不過這個東西我估計他常數也不會太小。但是不難寫,也許是乙個卡常的思路吧。

我不想寫了。

關於樹分塊演算法的一些研究

正統的分塊方法應該是如 王室聯邦 一題的分塊方法。樹塊具體定義如下 1 除根節點所在塊以外,每一塊內深度最小的結點的父親相同。這個父親被稱之為該塊的塊頂,其中特別的根節點也是塊頂。2 每一塊內非深度最小的結點的父親一定與其處於同一塊中。3 b 每塊大小 3b。b是你定義的乙個常數 b就是決定塊大小和...

分塊的九個基礎應用

quad 區間加法,單點詢問 quad 問題 給出乙個長為 n 的數列,以及 n 個操作,操作涉及區間加法,單點查值。quad 對每個塊加個 tag 即可。quad 區間加法,詢問區間內小於某個值 x 的元素個數 quad 問題 給出乙個長為 n 的數列,以及 n 個操作,操作涉及區間加法,詢問區間...

簡單又複雜的演算法 分塊

對於區間操作的問題,部分可以用分塊來做 事實上分塊還是蠻簡單的,主要是看分塊之後怎麼樣進行處理,它很靈活,沒有固定的模式 還是拿題目來舉例吧 bzoj 2002bzoj 3065 bzoj 2002 分塊版 include cstdio include cmath define maxn 20000...