一篇打臉文
打臉了...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!
一篇打臉文