這篇會理論上講一講常用的資料結構維護手法。
我是嘴巴選手我自豪!
①cdq分治
現在我們有一些修改,有一些詢問,修改之間獨立。
我們考慮分治,對於左右兩半分別分治,然後對於左邊的修改計算對右邊詢問的貢獻。
本身的複雜度是o(nlogn)。
②整體二分
現在我們有一些修改,有一些詢問。
我們需要求出,在最少多少組修改之後滿足題目條件。(或者可以轉化成這樣)
對於單組詢問,我會二分!對於多組詢問,真不巧,二分超時了...
我們考慮整體二分。整體二分的框架大概是這樣:
def本身的複雜度是o(nlogn)的。整體二分(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)
公升級版(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.在稍微複雜的線性表中,乙個資料元素可以由若干個資料項組成 ...