二叉查找树
Treap
treap数组版
Treap2
关于有旋treap的分离和合并
poj3481 Double Queue
这是一个Treap的模板题,之前学Treap的时候觉得看会了就没有写,结果写的时候果然改了半天bug。。
就当作模板吧
再提一句,指针写出来第一编太容易运行错误了,所以会更新数组的写法
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <string>
#include <cmath>
#include <cstdlib>
using namespace std;
struct Node
{
Node *lch,*rch;
int r,v,info;
//v为优先级,info为客户编号,r为rand()
};
void newnode(Node *&o,int val,int info)
{
o = new Node;
o->lch = o->rch = NULL;
o->info = info;//客户编号
o->v = val; //客户优先级
o->r = rand();
}
void left_rotate(Node *&o)
{
Node *t = o->rch;
o->rch = t->lch;
t->lch = o;
o = t;
}
void right_rotate(Node *&o)
{
Node *t = o->lch;
o->lch = t->rch;
t->rch = o;
o = t;
}
void Insert(Node *&o,int val,int info)
{
if(o == NULL){
newnode(o,val,info);
//cout<<val<<' '<<info<<endl;
return ;
}
//大于该节点,就往右子节点找
if(val > o->v){
Insert(o->rch,val,info);
//插入之后,还要旋转去维持根堆
if(o->rch->r > o->r){
left_rotate(o);
}
}
else{
Insert(o->lch,val,info);
if(o->lch->r > o->r ){
right_rotate(o);
}
}
}
//删除选定优先级的节点
void remove(Node *&o,int val)
{
//如果找到了这个要删除的节点
if(val == o->v){
//如果这个节点的子节点数为2,那么直接就根据子节点的r值判断向哪个方向旋转
if(o->lch != NULL && o->rch != NULL){
//如果左子节点大,就右旋,另一种情况则相反
if(o->lch->r > o->rch->r){
right_rotate(o);
//然后向旋转的方向继续删除
remove(o->rch,val);
}
else{
left_rotate(o);
remove(o->lch,val);
}
}
else{
Node *t = o;
//至少一个子节点为空时,直接替换要删除的这个节点(如果不存在字节点,就等于是用NULL替换这个节点)
if(o->lch == NULL){
o = o->rch;
}
else {
o = o->lch;
}
//cout<<t->v<<' '<<t->info<<endl;
delete t;
}
}
else{
//如果不是要找的节点,就继续向下找
if(val >=o->v){
remove(o->rch,val);
}
else{
remove(o->lch,val);
}
}
}
int find_MAX(Node *o)
{
//如果当前节点右子树为空,那么这个点就是最大的节点
if(o->rch == NULL){
//找到后输出该客户的编号,并返回该客户优先级,以用于删除该节点
printf("%d\n",o->info);
return o->v;
}
//如果没找到,继续查找右字节点
return find_MAX(o->rch);
}
int find_MIN(Node *o)
{
//如果当前节点左子树为空,那么这个点就是最小的节点
if(o->lch == NULL){
//找到后输出该客户的编号,并返回该客户优先级,以用于删除该节点
printf("%d\n",o->info);
return o->v;
}
//如果没找到,继续查找左子节点
return find_MIN(o->lch);
}
int main()
{
int op;
Node *rt = NULL;
while (scanf("%d",&op) == 1&& op)
{
if(op == 1){
int info,val;
scanf("%d%d",&info,&val);
Insert(rt,val,info);
}
else if(op == 2){
if(rt == NULL){
printf("0\n");
continue;
}
int v = find_MAX(rt);
remove(rt,v);
}
else{
if(rt == NULL){
printf("0\n");
continue;
}
int v = find_MIN(rt);
remove(rt,v);
}
}
return 0;
}
经过了半天的debug,又贴出了数组版本,全是血泪啊
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <string>
#include <cmath>
#include <cstdlib>
using namespace std;
const int MAXN = 100005;
struct Node
{
int left,right,r,v,info;
//v为优先级,info为客户编号,r为rand()
}node[MAXN];
int cnt;
void newnode(int &o,int val,int info)
{
cnt++;
o = cnt;
node[cnt].info = info;
node[cnt].v = val;
node[cnt].left = node[cnt].right = 0;
node[cnt].r = rand();
}
void left_rotate(int &o)
{
int t = node[o].right;
node[o].right = node[t].left;
node[t].left = o;
o = t;
}
void right_rotate(int &o)
{
int t = node[o].left;
node[o].left = node[t].right;
node[t].right = o;
o = t;
}
void Insert(int &o,int val,int info)
{
if( !o ){
newnode(o,val,info);
//cout<<info<<' '<<val<<endl;
return ;
}
//大于该节点,就往右子节点找
if(val > node[o].v){
Insert(node[o].right,val,info);
//插入之后,还要旋转去维持根堆
if(node[node[o].right].r > node[o].r){
left_rotate(o);
}
}
else{
Insert(node[o].left,val,info);
if(node[node[o].left].r > node[o].r ){
right_rotate(o);
}
}
}
//删除选定优先级的节点
void remove(int &o,int val)
{
//如果找到了这个要删除的节点
if(val == node[o].v){
//如果这个节点的子节点数为2,那么直接就根据子节点的r值判断向哪个方向旋转
if(node[o].left != 0 && node[o].right != 0){
//如果左子节点大,就右旋,另一种情况则相反
if(node[node[o].left].r > node[node[o].right].r){
right_rotate(o);
//然后向旋转的方向继续删除
remove(node[o].right,val);
}
else{
left_rotate(o);
remove(node[o].left,val);
}
}
else{
//至少一个子节点为空时,直接替换要删除的这个节点(如果不存在字节点,就等于是用NULL替换这个节点)
if( !node[o].left ){
o = node[o].right;
}
else {
o = node[o].left;
}
//cout<<node[t].info<<' '<<node[t].v<<endl;
//delete t;
}
}
else{
//如果不是要找的节点,就继续向下找
if(val > node[o].v){
remove(node[o].right,val);
}
else{
remove(node[o].left,val);
}
}
}
int find_MAX(int o)
{
//如果当前节点右子树为空,那么这个点就是最大的节点
if( !node[o].right ){
//找到后输出该客户的编号,并返回该客户优先级,以用于删除该节点
printf("%d\n",node[o].info);
return node[o].v;
}
//如果没找到,继续查找右字节点
return find_MAX(node[o].right);
}
int find_MIN(int o)
{
//如果当前节点左子树为空,那么这个点就是最小的节点
if( !node[o].left ){
//找到后输出该客户的编号,并返回该客户优先级,以用于删除该节点
printf("%d\n",node[o].info);
return node[o].v;
}
//如果没找到,继续查找左子节点
return find_MIN(node[o].left);
}
int main()
{
int op;
int rt = 0;
while (scanf("%d",&op) == 1&& op)
{
if(op == 1){
int info,val;
scanf("%d%d",&info,&val);
Insert(rt,val,info);
}
else if(op == 2){
if( !rt ){
printf("0\n");
continue;
}
int v = find_MAX(rt);
remove(rt,v);
}
else{
if( !rt ){
printf("0\n");
continue;
}
int v = find_MIN(rt);
remove(rt,v);
}
}
return 0;
}