塊狀鍊錶(STL rope)

2021-10-14 00:22:12 字數 1942 閱讀 1531

塊狀鍊錶(stl rope)

首先介紹一下塊狀鍊錶。

我們都知道:

陣列 具有 o(1)的查詢時間,o(n)的刪除,o(n)的插入。

鍊錶 具有 o(n)的查詢時間,o(1)的刪除,o(1)的插入。

既然陣列和鍊錶各有優劣,那麼我們為何不將鍊錶和陣列組合起來,一起來均攤時間呢?

做法就是維護乙個鍊錶,鍊錶中的每個單元包含一段陣列,以及這個陣列中的資料個數。每個鍊錶中的資料連起來就是整個資料。

設煉表的長度為a,每個單元中陣列的長度為b。那麼無論是插入還是刪除,在定址的時候都要遍歷整個鍊錶,複雜度是o(a);

對於插入操作,如果直接在鍊錶中加入乙個新的單元,時間複雜度是o(1),如果要在乙個單元內插入乙個新的數,那麼則需要移動陣列中的資料,複雜度是o(b),總的複雜度是o(a + b)。

對於刪除操作,可能會涉及多個連續的單元,如果乙個單元中的所有資料均要刪除,直接刪除這個單元,複雜度是o(1),如果只刪除部分的資料,則要移動陣列中的資料,複雜度是o(b)。總的複雜度是o(a + b)。

因為ab = n,取a = b = √n,則總的複雜度是o(2√n)= o(√n)

問題是如何維護a和b大致等於√n?

插入操作:

每個鍊錶節點的資料是乙個陣列塊,那麼問題來了,我們是根據什麼將陣列切開呢?總不能將所有的資料都放在乙個鍊錶的節點吧,那就退化成陣列了。在理想的情況下,為了保持√n的陣列個數,所以我們定了乙個界限2√n,當鍊表中的節點陣列的個數超過2√n的時候,當下次插入資料的時候,我們有兩種做法:

① 在元素的陣列插入處,將當前陣列切開,插入元素處之前為乙個鍊錶節點,插入元素後為乙個鍊錶節點。

② 將元素插入陣列後,將陣列從中間位置切開。

刪除操作:

跟插入道理一樣,既然有裂開,就有合併,我們同樣定義乙個界限值√n/2,當鍊表節點的陣列個數小於這個界限值的時候,就需要將此節點和後面的鍊錶節點進行合併。

執行上述維護操作需要移動陣列中的資料,複雜度是o(b),對於單元的分割和合併均是o(1)的,總的複雜度是o(b)的。這樣,維護操作並不會使總複雜度增加。最終得到乙個複雜度是o(√n)的資料結構。

rope**(可持久化平衡樹)

【可持久化線段樹?!】rope史上最全詳解

這裡注意rope是支援"+"操作的。題目

問題很簡單,但是需要涉及到區間的操作,用rope暴力就行。複雜度為o(n√n)。

#include

#include

#define ll long long

#define inf 0x3f3f3f3f

#define endl '\n'

#define ios std::ios::sync_with_stdio(false),cin.tie(0), cout.tie(0)

using

namespace std;

using

namespace __gnu_cxx;

const

int n =

1e5+10;

rope<

int>r;

int n, m, a, b;

intmain()

for(

int i =

0; i < n; i ++

)printf

("%d "

, r[i]);

return0;

}

塊狀鍊錶模板

塊狀鍊錶 下標從0開始 塊大小和塊數設為比sqrt n 稍大 const int n 2000000 10,block sz 4000 100,block num 4000 10 queue que int head char str n struct block g block num int n...

塊狀鍊錶與塊狀樹初步

1.塊狀鍊錶的基本思想 常見的線性表結構修改操作有 再某一位置後插入一段數,從某一位置開始刪除連續若干個數,我們不妨先來看看陣列和鍊錶這兩種常用線性結構的實現效果。可見,它們各有各的優勢和缺點,且恰巧是優勢互補。我們不禁想,如果把兩者結合起來,是不是會有更優異的表現?塊狀鍊錶正好是基於這個思想,將陣...

塊狀鍊錶全紀錄

塊狀鍊錶的簡單介紹 塊狀鍊錶,可以說是一種很犯規的資料結構 支援動態的序列加入刪除,詢問區間和之類的操作 同時擁有陣列和鍊錶的優點 陣列 所有資料在記憶體中是緊湊儲存的,優點是定位快 o 1 鍊錶 通過指標將不同位置的元素鏈結起來 修改快 o 1 總的來說重要操作只有幾個 定位,插入,合併 塊狀鍊錶...