![COGS2421 [HZOI 2016]简单的Treap COGS2421 [HZOI 2016]简单的Treap](https://image.shishitao.com:8440/aHR0cHM6Ly9ia3FzaW1nLmlrYWZhbi5jb20vdXBsb2FkL2NoYXRncHQtcy5wbmc%2FIQ%3D%3D.png?!?w=700&webp=1)
大概是个模板题
Treap暴力插入的做法太暴力了并不优美
这里就需要用到笛卡尔树的构造方法,定义见这里
在 假的O(n) 的时间内构造一棵Treap
把元素从小到大排序
这样从小到大插入时,只会往树上最右边的链上走
这样考虑一下 Treap 正常的 Insert 的过程:
只要找到第一个优先级更小(大根堆)的节点,将待插入节点插到上一层的右儿子的位置
将当前找到的节点作为待插入节点的左儿子
这样就类似一个旋转操作,也就成功的模拟实现出了一个的 Treap 完整的 Insert 的过程
具体在代码里是这样的:
用一个单调栈维护整个树的最右边的链
边找符合要求的节点边出栈
找到之后进行上面提到的操作即可
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cstdio>
#include<stack>
using namespace std; const int MAXN = 500001; struct Node{
int ch[2], val, prio;
Node(){ch[0] = ch[1] = val = 0;}
bool operator < (const Node &b) const{
return val < b.val;
}
}t[MAXN];
int n, top, stk[MAXN]; inline int rd() {
register int x = 0;
register char c = getchar();
register bool f = false;
while(!isdigit(c)) {
if(c == '-') f = true;
c = getchar();
}
while(isdigit(c)) {
x = x * 10 + (c ^ 48);
c = getchar();
}
return f ? -x : x;
}
stack<int> dfs;
bool vis[MAXN];
void Recycle() {
dfs.push(stk[1]);
vis[0] = true;
while(dfs.size()) {
int cur = dfs.top();
if(!vis[cur]) {
vis[cur] = true;
printf("%d ", t[cur].val);
}
if(!vis[t[cur].ch[0]]) dfs.push(t[cur].ch[0]);
else if(!vis[t[cur].ch[1]]) dfs.push(t[cur].ch[1]);
else dfs.pop();
}
return;
} int main() {
freopen("treap.in", "r", stdin);
freopen("treap.out", "w", stdout);
n = rd();
for(int i = 1; i <= n; ++i) t[i].val = rd();
for(int i = 1; i <= n; ++i) t[i].prio = rd();
sort(t + 1, t + n + 1);
stk[++top] = 1;
for(int i = 2; i <= n; ++i) {
int last = 0;
while(top and t[stk[top]].prio > t[i].prio) last = stk[top--];
t[i].ch[0] = last;
if(top) t[stk[top]].ch[1] = i;
stk[++top] = i;
}
//printf("root %d\n", stk[1]);
Recycle();
fclose(stdin);
fclose(stdout);
return 0;
}