1. 程式人生 > >一篇打臉文

一篇打臉文

最值 更新 第一個 是我 發現 一個 兩種 數值 所有

打臉了...Splay其實有兩種用法,第一個是常數奇大的平衡樹

而第二個就厲害了,Splay可以對區間進行操作

具體是怎麽個意思呢,我們來看這樣一件事情

對於一個數列,我們用Splay維護它的下標

然後我們進行下面的Split操作

1.將l-1旋轉到根

2.將r+1旋轉到l-1的右兒子

令a為r+1的左子樹

然後我們驚奇的發現a這棵子樹表示了區間[l,r]

然後...我們就可以對a為所欲為了

當然要註意,l-1指的是數值,而不是點,所以我們需要借用Splay作為平衡樹時的一個函數:find()來找到l-1存在哪個位置

然後...我們就可以為所欲為啦

1. 插入、刪除:

對於插入操作,我們可以將x轉到根部,再將x+1轉到x下方然後在x+1的左子樹中插入新節點即可。
那麽類似的對於刪除,我們也可以先將x-1轉到根部,x+1轉到根下方,那麽x就是x+1的左子樹,直接刪除即可~

2. 詢問:

對於詢問區間(x,y)的最值,只需將x-1轉到根,然後將y+1轉到x-1的下方,於是我們需要維護的區間就在y+1的左子樹的所有點的集合裏了,直接輸出節點信息即可。

3. 翻轉、區間增加:

和詢問類似,先將x-1轉到根,然後將y+1轉到x-1的下方,然後對y+1的左子樹打標記即可~,註意及時更新標記。

4. 滾動:

可以發現,滾動某個區間就等價於交換區間的兩部分,我們設這個中點為z,那麽我們的目的就是交換(x, z) 和 (z+1, y), 我們可以先將z轉到根,然後將y+1轉到z的下方,於是y+1的左子樹就對應了區間(z+1,y)然後我們將這一段切下來,繼續將x-1轉到根,再將x轉到x-1下方,最後將區間(z+1, y)接到x-1的左邊即可。

最後一個問題,怎麽輸出呢?

註意到我們建Splay的時候,其實它的中序遍歷就是原數組,我們寫一個遞歸的print()函數就可以了...

之前還一直以為Splay只是一個平衡樹...

真是Naive!

一篇打臉文