类似笛卡尔树的实现:
http://baike.baidu.com/link?url=nDGlKta6rvBzJ4_xm1TSp-Px05bU6gzgqWx7LnWwnXm5brtOCPJXXXRXeq9ZpIvsfrWkhua4D76oWrt2iQq2WK
从题目可以看出,按 a 来看的话,是一个二叉排序树,按 b 来看的话,是一个大根堆.
然后需要知道一个性质:二叉排序树的中序遍历,可以得到一个递增的序列。
(1) build:
解法1: 将 pair[] 按照 b 大到小排序,这样的话,第一个,肯定就是树的根节点,继续遍历 pair[],按照 a 的值来分配这个结点的位置。
比如 t->a > insert.a , 这样的话,就往t右子树继续找,如果t->a < insert.a ,就往t右子树继续找,每次t 从根节点开始。
这样的效率为 Nlog(N);
解法2: 将 pair[] 按照 a 小到大排序,然后在遍历 pair[] 来构建树,因为排序过,所以带插入地 insert 肯定是在当前树中 a 最大的那个,
这样就会出现两种情况: 1. insert.b > t.b ,则,insert 取代 t 的位置,然后 insert.left = t;
2.insert.b < t.b ,则,继续与 t.right.b 比较,因为,insert.a 是当前最大,肯定去右边,直至出现 1 的情况,或者到一个空子树,则插入。
这样的效率也是为 Nlog(N);
解法3:在解法2的基础上改进,因为每次都是从根节点开始进行比较,就会多需要一点时间,然后,我们就用一个 stack 来保存 根节点,根节点的右子树的结点(栈底为根节点) .....因为插入的 a 是最大的,肯定先跟最右的比较,1.如果 insert.b < stack.top.b ,则,stack.top.right = insert.,然后多了个右结点,进栈;2.如果 insert.b > stack.top.b , 则说明,需要回溯上去,再跟 stack--.top.b 比较,如果出现 1 的情况,则,在那之前的右子树,成为 insert.left. insert 进栈;或者出现,所有栈都出去了,说明这个 insert 即将成为新的树根。利用空间换时间,效率为 O(N);
(2)insert();
解法: 先按照 二叉排序树的性质,按a的大小将其插入为一个叶子结点,插入之后,进行 b 的判断,如果是左子树插入,且 插入的 b 比较大,则以他的父节点进行一次右旋转,反之,如果是在右子树插入,且插入的 b 比较大,则以他的父节点进行一次左旋转;回溯到根结点.
void treap_insert(treap_node*&a,int label,int p) { if(!a) { a=new treap_node; a->label=label; a->p=p; } else if(label<a->label) { treap_insert(a->left,label,p); if(a->left->p>a->p) treap_right_rotate(a); } else { treap_insert(a->right,label,p); if(a->right->p>a->p) treap_left_rotate(a); } }