最近學習了splay和非旋式treap,於是找到了這道題。
維護乙個序列,支援移動元素,查詢元素在序列中的位置,查詢序列中某乙個位置的元素。
無旋式treap可以維護一棵樹的中序遍歷結果,但是不支援通過編號來找節點。於是在無旋式treap的基礎上,維護每個節點的父親,這樣就可以求出元素在序列中的位置。
對於乙個節點,每次將它向樹根跳如果它是父親的右兒子,那麼就將它父親的左子樹大小+1+1
+1計入結果
那麼如何計算父親呢?顯然,會改變父親的只有split和merge操作,那麼我只需要在這兩個函式中修改就可以了。在split的時候再傳兩個引數記錄父親,merge 的時候在修改兒子的同時將父親一起修改。
其他的都是無旋式treap的基本操作了。
#include
#define ll long long
#define inf 0x3f3f3f3f
#define pi 3.1415926535897932384626
using
namespace std;
inline
intread()
ch=getchar()
;}while
(isdigit
(ch)
)return w*s;
}const
int maxn=
8e4+10;
int n,m,id[maxn]
,a[maxn]
,root,r1,r2,r3,r4,cnt=0;
//id記錄某乙個書的編號對映到樹中的節點的編號
struct treapt[maxn]
;int
newnode
(int val)
voidup(
int x)
void
split
(int x,
int k,
int&a,
int&b,
int faa=0,
int fab=0)
if(k<=t[t[x]
.ch[0]
].size)
else
up(x);}
intmerge
(int x,
int y)
//直接在記錄兒子的時候同時修改父親
if(t[x]
.rd.rd)
else
}void
insert
(int pos,
int val)
bool
get(
int x)
intfind
(int cnt)
//cnt是節點編號
cnt=t[cnt]
.fa;
//因為若該節點時左兒子的話,向上走時中序遍歷在增大的
//如果是右兒子往上跳的話,父親的左子樹的所有節點的中序遍歷的結果都是小於我在查的節點,所以要計入答案
}return res;
}int
main()
char opt[
100]
;for
(int i=
1;i<=m;i++
)case
'b':
case
'i':
else
}break;}
case
'a':
case
'q':}}
return0;
}
題解 ZJOI2006 書架
link 小 t 有乙個很大的書櫃。這個書櫃的構造有些獨特,即書櫃裡的書是從上至下堆放成一列。她用 1 到 n 的正整數給每本書都編了號。小 t 在看書的時候,每次取出一本書,看完後放回書櫃然後再拿下一本。由於這些書太有吸引力了,所以她看完後常常會忘記原來是放在書櫃的什麼位置。不過小 t 的記憶力是...
ZJOI2006 書架 平衡樹
題目描述 小t有乙個很大的書櫃。這個書櫃的構造有些獨特,即書櫃裡的書是從上至下堆放成一列。她用1到n的正整數給每本書都編了號。小t在看書的時候,每次取出一本書,看完後放回書櫃然後再拿下一本。由於這些書太有吸引力了,所以她看完後常常會忘記原來是放在書櫃的什麼位置。不過小t的記憶力是非常好的,所以每次放...
洛谷P2596 書架 splay
給出 n 本書和 m 個操作,按照操作維護序列並輸出對應結果。建立書本編號對樹上節點的對映,對於 top 和 bottom 操作,先把其前驅旋到根,後繼旋到根的右兒子,目標節點就是根的右兒子的左兒子。記錄其節點編號,然後斷開,把節點加到樹的最前或者最後。對於 insert 操作,如果是 0 直接忽略...