一些常用的資料結構維護手法

2022-02-02 06:16:14 字數 3122 閱讀 9107

這篇會理論上講一講常用的資料結構維護手法。

我是嘴巴選手我自豪!

①cdq分治

現在我們有一些修改,有一些詢問,修改之間獨立。

我們考慮分治,對於左右兩半分別分治,然後對於左邊的修改計算對右邊詢問的貢獻。

本身的複雜度是o(nlogn)。

②整體二分

現在我們有一些修改,有一些詢問。

我們需要求出,在最少多少組修改之後滿足題目條件。(或者可以轉化成這樣)

對於單組詢問,我會二分!對於多組詢問,真不巧,二分超時了...

我們考慮整體二分。整體二分的框架大概是這樣:

def

整體二分(el,er,ql,qr):

if el==er:

ql到qr的答案都是el

return

em=(el+er)/2模擬el...em的操作

看一下ql...qr哪些滿足了

滿足的放到ql...qm,不滿足的放到qm+1...qr

整體二分(em+1,er,qm+1,qr)

撤銷el...em的操作

整體二分(el,em,ql,qm)

本身的複雜度是o(nlogn)的。

公升級版(upd 2017.7.19)

有n條邊,每條邊有乙個邊權,對於每個i,你要對前i條邊回答,加上邊權<=幾的邊會沒有奇數大小的聯通塊。

def

go(l,r,al,ar): #

表示現在考慮操作[l,r],答案邊權在[al,ar]

#編號mid=(l+r)/2記錄乙個狀態ver

for i in

[l,mid]:

如果i操作的邊邊權比al小就加邊

nmid=-1

for i in

[al,ar]:

如果邊權為i的邊,操作編號為[l,mid]就加邊

如果沒有奇數聯通塊了:

nmid=i

break

回到狀態ver

if nmid==-1:

[l,mid]答案為-1

for i in

[l,mid]:

如果i操作的邊邊權比al小就加邊

go(mid+1,r,al,ar)

回到狀態ver

return

ans[mid]=nmid

for i in [al,nmid-1]:

如果邊權為i的邊,操作編號在[1,l-1]就加邊

go(l,mid-1,nmid,ar)

回到狀態ver

for i in

[l,mid]:

如果i操作的邊邊權比al小就加邊

go(mid+1,r,al,nmid)

回到狀態ver

③時間倒流

現在我們有一些修改(例如刪除邊啥的),有一些詢問。

修改反著做比正著做容易。

既然可以離線,乾脆把修改倒過來做。

④根號重構

現在我們有一些修改,有一些詢問,修改之間獨立。

對於一堆修改計算對一堆詢問的貢獻複雜度比較高(例如和詢問修改個數無關,而和其它東西有關),而單個修改對單個詢問貢獻複雜度很低。

同時我們可以用相對比較低的複雜度把一坨修改預處理一波,計算預處理之後的東西對單個詢問貢獻複雜度很低。

我們可以每根號個修改預處理一次,然後詢問就列舉還沒預處理的修改以及預處理好的算貢獻就可以了。

本身的複雜度是o(n√n)。

⑤莫隊a.

現在我們沒有修改,只有一大堆詢問。

詢問十分複雜,但是如果知道了[l,r]的答案,可以很快得到[l,r-1]和[l,r+1]和[l-1,r]和[l+1,r]的答案。

考慮把l分成根號塊,把所有詢問排序,按l所在的塊編號為第一關鍵字,r為第二關鍵字排序,暴力拓展當前的區間。

本身的複雜度是o(n√n)。

b.(upd 2017.03.19)

現在我們沒有修改,只有一大堆詢問。

詢問十分複雜,但是如果知道了[l,r]的答案,可以很快得到[l,r+1]和[l-1,r]的答案。

設p=sqrt(n),那麼對於長度<=2p的詢問先暴力做。

對於長度》2p的,考慮把左端點按p間距分塊,每次考慮左端點在同一塊中的所有詢問。

對於左端點在一塊的詢問,假裝塊範圍為[l,r],把這坨詢問按右端點排序,假設某個詢問為[p,q],那麼首先考慮[r+1,q],因為q是遞增的,所以大概可以拿個指標掃一遍,然後再插入[p,r],插入完再撤銷。(既然能插入顯然也能撤銷,大不了把所有修改過的記憶體位址記下來)

本身的複雜度還是o(n√n)。

⑥線段樹分治

現在我們有一些區間修改,有一些單點詢問,詢問在所有修改之後。

a.比較容易支援對當前狀態進行修改,並撤銷這次修改(如果不再進行其它修改)。

複雜度是o(nlogn*(修改/撤銷)+n*詢問)。

b.(upd 2016.12.26)

比較容易支援處理出乙個區間的資訊,詢問資訊可以合併。

還是對於區間建出線段樹結構(只要結構),對於每個修改下放到log個區間,對於每個線段樹節點預處理資訊,單點詢問時把它到線段樹根節點上的鏈每個資訊都查詢一遍,合併在一起。

實際寫的時候可以把詢問先全部扔到鏈上的每個節點上,不用真的實時查詢。

複雜度是o(nlogn*修改+nlogn*詢問)。

一般來說b比較優秀,除非詢問的東西實在比較特殊,詢問大概慢乙個log這樣,而且還要茲磁撤銷(我猜並沒有這種題目?)

⑦二進位制分組

我們可以以乙個與修改個數有關的時間預處理出一些修改的資訊,對於乙個詢問可以快速地在預處理後的一些修改中獲取資訊。

我們可以採用二進位制分組的思想,感覺這種做法只能看圖了...

本身的複雜度是o(nlogn)。

⑧分治(upd 2017.03.22)

現在有一些詢問,詢問靜態區間中一段的某些資訊。詢問支援離線,資訊容易儲存,用單點更新資訊比資訊合併快乙個log。

考慮對於序列分治,每次把序列切成兩段,考慮跨兩段的詢問,只要斷點前後做一次前字尾和,對於詢問合併一下乙個字尾和乙個字首就好了。

假設資訊合併是o(log)的,更新單點是o(1)的,那麼複雜度就是o(nlogn)的。

一些資料結構

dir heapq about all builtins cached doc file loader name package spec heapify max heapreplace max siftdown siftdown max siftup siftup max heapify heap...

資料結構中一些常用的演算法

1.計算二項式係數 動態規劃 coding utf 8 computing c n,k def binomial coefficient n,k if k 0 or k n result 1 else result binomial coefficient n 1,k 1 binomial coef...

資料結構的一些筆記

資料結構 1.邏輯結構 書中都是對邏輯結構的討論 幫助理解 人為抽象出來的結構 線性 表 非線性 圖,樹 2.儲存結構 物理結構 幫助理解 資料到底以什麼樣的形式儲存在計算機中 順序 鏈式 線性表1.線性表是最常用且最簡單的一種資料結構 2.在稍微複雜的線性表中,乙個資料元素可以由若干個資料項組成 ...