前言
Splay是會轉的的好,Treap是不會轉的妙,我們不用轉也能實現神奇的操作
在這裡比較複雜的是插入區間的操作,這是Treap沒有嘗試過的
如何O(n)O(n)構造Treap?
Splay可以遞歸構造,但是Treap有key的問題,顯然不能那樣構造
那怎麼構造呢?
我們利用棧來解決這個問題
我們將每次構造出來的節點放到棧裏,當我們再次要構造一個新節點時,我們和棧頂節點比較,有兩種情況停止比較
- 棧頂元素key值的優先度高於新節點
- 棧空了
我們將最後一個彈出的節點接在新節點的左兒子上
如果棧未空,我們就將新節點接在棧頂的右兒子上
最後將新節點壓入棧
不要忘了將每個節點都Pushup一下
這個操作玄學滿足中序遍曆為原序列,而且造出了一個平衡的Treap
不知道是誰想出的神奇操作
inline node *build(int k)
{
int top=0,a;
for(int i=1;i<=k;i++)
{
read(a);
node *temp=new node(a),*last=nil;
while(top&&stack[top]->key>temp->key)
stack[top]->push_up(),last=stack[top],stack[top--]=nil;
if(top)stack[top]->son[1]=temp;
temp->son[0]=last,stack[++top]=temp;
}
while(top)
stack[top--]->push_up();
return stack[1];
}
只有這裡最難
下面我把每個函數分開發上來
節點定義
struct node
{
int val,key,size,sum,maxsum,lmax,rmax;
bool rev,same;
node *son[2];
node(int x);
node(){}
~node();
inline void push_up();
inline void push_down();
inline void push_rev();
inline void push_same(int x);
}*nil=new node(0),*Root,*stack[MAXN];
pair模板
template<class a,class b>class Pair
{
public:
a first;
b second;
Pair(){}
Pair(a x,b y){
first=x,second=y;}
};
讀入輸出優化
inline void read(int &x)
{
int s=0,w=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')w=-1;c=getchar();}
while(c<='9'&&c>='0'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
x=s*w;
}
inline void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
隨機數生成器優化