线段树-Count on a Treap-神题
Count on a Treap
題目來源
Codechef Feb 2014 COT5
https://www.codechef.com/problems/COT5
問題提出
什么是Treap
- 是一顆二叉搜索樹,每個節點擁有keykeykey屬性.
- 是一顆堆,每個節點擁有weightweightweight屬性
問題
- nnn次操作,三種類型,要求維護"大根Treap"
- (0,k,w)(0,k,w)(0,k,w) ,插入keykeykey為k,weightk,weightk,weight為www的點.
- (1,k)(1,k)(1,k),刪除keykeykey為kkk的點
- (2,ku,kv)(2,k_u,k_v)(2,ku?,kv?),詢問keykeykey為ku,kvk_u,k_vku?,kv?的兩點在TreapTreapTreap中的距離.
保證keykeykey,weightweightweight均不相同.
問題解答
dist(u,v)=dep(u)+dep(v)?2?dep(lca)dist(u,v) = dep(u) + dep(v) - 2* dep(lca)dist(u,v)=dep(u)+dep(v)?2?dep(lca)
我們以keykeykey為下標,將這個樹按中序遍歷展開.
顯然[ku,kv][k_u,k_v][ku?,kv?]之間最大的weightweightweight最大的點就是兩點的lcalcalca.
證明:首先lcalcalca一定在區間[ku,kv][k_u,k_v][ku?,kv?]之間,不然ku,kvk_u,k_vku?,kv?將位于lcalcalca的同一側,這不可能.其次權重最大的點一定是這顆子樹的根節點,這個點一定是祖先,如果它不是lcalcalca的話,那么它的keykeykey將大于或小于lcalcalca形成的子樹中所有的點的keykeykey,也就是說它不在區間[ku,kv][k_u,k_v][ku?,kv?]之間,矛盾.
至此,用線段樹可以輕松維護lcalcalca.
那么如何維護一個點在樹上的深度呢?
根據Treap的特殊性質,我們知道每個點的weightweightweight一定小于他父親的weightweightweight.
從這個點到根節點的祖先鏈上的weightweightweight是不斷遞增的.
這里有一個非常特殊的性質,在序列上就是從這個點往兩側各找一個直接的遞增子序列,那么序列上的點都是他的祖先.
這個性質基于這樣一個事實:每個點左右兩側的第一個大于它weightweightweight的點,都是這個點的一個祖先.因為其中一個點是它的父親,而另一個點…自己畫圖觀察一下就好了.
因此兩個遞增序列的長度和就是它到根的距離.
如何維護某一個點向右的直接遞增序列呢.也是使用線段樹,參考我的另一篇博客,樓房重建.
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的线段树-Count on a Treap-神题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 线段树-Chossing Ads-分治,
- 下一篇: 线段树-楼房重建-洛谷-P4198