COGS2421 [HZOI 2016]简单的Treap
大概是个模板题
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; }
禁止诸如开发者知识库/布布扣/码迷/学步园/马开东等 copy 他人博文乃至博客的网站转载
,用户转载请注明出处:https://www.cnblogs.com/xcysblog/