Treap学习笔记

Treap是为了解决BST(二叉查找树)退化成链的问题
Tree=tree+heap
即在BST的基础上多了一个信息:优先级
优先级就按照堆的性质维护
若是大根堆,将优先级高的转到树的上面
前提是保证BST的性质,即中序遍历不变,如图:

观察发现,前一个图的a向上旋转后,中序遍历不变(当然,右图的b向上转后就是左图)

代码:

void rotate(int &o,int pd){
    int t=tree[o].son[pd];
    tree[o].son[pd]=tree[t].son[1-pd];
    tree[t].son[1-pd]=o;
    o=t;
}

它支持的操作和BST一样

插入:
递归插入,大于当前节点就到右儿子,小于就到左儿子,同时维护优先级

//小根堆
void Insert(int &o,int x){
    if(!o){
        o=++js;
        tree[js].val=x;
        tree[js].size=1;
        tree[js].rad=rand();
        return ;
    }
    if(x==tree[o].val) tree[js].size++;
    else if(x<tree[o].val){
        Insert(tree[o].son[0],x);
        if(tree[tree[o].son[0]].rad<tree[o].rad)
          rotate(o,0);
    }
    else {
        Insert(tree[o].son[1],x);
        if(tree[tree[o].son[1]].rad<tree[o].rad)
          rotate(o,1);
    }
}

删除:
把要删除的点向下调整,用儿子中优先级较高的代替当前节点,直到调整到叶节点,直接删除

//小根堆
void Del(int &o,int x){
    if(tree[o].val==x){
        if(tree[o].size>1) tree[o].size--;
        else if(tree[o].son[0]*tree[o].son[1]==0) o=tree[o].son[1]+tree[o].son[0];//叶节点
            else if(tree[tree[o].son[0]].rad<tree[tree[o].son[1]].rad)
                rotate(o,0),Del(o,x);
            else rotate(o,1),Del(o,x);
    }
    else if(x<tree[o].val) Del(tree[o].son[0],x);
    else Del(tree[o].son[1],x);
}

找第K大:
比较k和左子树的大小,递归寻找

int K_th(int k){
    QAQ t=rot;
    while(1){
        if(tree[tree[t].son[0]].size>=k) t=tree[t].son[0];
        else if(tree[tree[t].son[0]].size+tree[t].js==k) return tree[t].val;
        else k-=tree[tree[t].son[0]].size+tree[t].js,t=tree[t].son[1];
    }
}

例题:

洛谷 鬼子进村

题目背景

小卡正在新家的客厅中看电视。电视里正在播放放了千八百次依旧重播的《亮剑》,剧中李云龙带领的独立团在一个县城遇到了一个鬼子小队,于是独立团与鬼子展开游击战。

题目描述

描述 县城里有n个用地道相连的房子,第i个只与第i-1和第i+1个相连。这是有m个消息依次传来

1、消息为D x:鬼子将x号房子摧毁了,地道被堵上。

2、消息为R :村民们将鬼子上一个摧毁的房子修复了。

3、消息为Q x:有一名士兵被围堵在x号房子中。

李云龙收到信息很紧张,他想知道每一个被围堵的士兵能够到达的房子有几个。

输入输出格式

输入格式:
第一行2个整数\(n,m(n,m\leq500000)\)

接下来\(m\)行,有如题目所说的三种信息共m条。

输出格式:
对于每一个被围堵的士兵,输出该士兵能够到达的房子数。

输入输出样例

输入样例#1:

7 9
D 3
D 6
D 5
Q 4
Q 5
R
Q 4
R
Q 4

输出样例#1:

1
0
2
4

说明

若士兵被围堵在摧毁了的房子中,那只能等死了。。。。。。

题解:用Treap维护被摧毁的房子,询问时找大于当前房子编号的最小编号和小于当前房子编号的最大编号,它俩之间的房子个数即为答案

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<bitset>
#include<sstream>
#include<cstdlib>
#define QAQ int
#define TAT long long
#define OwO bool
#define ORZ double
#define F(i,j,n) for(QAQ i=j;i<=n;++i)
#define E(i,j,n) for(QAQ i=j;i>=n;--i)
#define MES(i,j) memset(i,j,sizeof(i))
#define MEC(i,j) memcpy(i,j,sizeof(j))

using namespace std;
const QAQ N=50005;
const QAQ Big=1e8;

QAQ n,m,js,rot,sta[N],tot;
struct data{
    QAQ son[2],size,val,rad;
}tree[N];
QAQ s,t;

void rotate(QAQ &o,QAQ pd){
    QAQ t=tree[o].son[pd];
    tree[o].son[pd]=tree[t].son[1-pd];
    tree[t].son[1-pd]=o;
    o=t;
}

void Insert(QAQ &o,QAQ x){
    if(!o){
        o=++js;
        tree[js].val=x;
        tree[js].size=1;
        tree[js].rad=rand();
        return ;
    }
    if(x==tree[o].val) tree[js].size++;
    else if(x<tree[o].val){
        Insert(tree[o].son[0],x);
        if(tree[tree[o].son[0]].rad<tree[o].rad)
          rotate(o,0);
    }
    else {
        Insert(tree[o].son[1],x);
        if(tree[tree[o].son[1]].rad<tree[o].rad)
          rotate(o,1);
    }
}

void Del(QAQ &o,QAQ x){
    if(tree[o].val==x){
        if(tree[o].size>1) tree[o].size--;
        else if(tree[o].son[0]*tree[o].son[1]==0) o=tree[o].son[1]+tree[o].son[0];
            else if(tree[tree[o].son[0]].rad<tree[tree[o].son[1]].rad)
                rotate(o,0),Del(o,x);
            else rotate(o,1),Del(o,x);
    }
    else if(x<tree[o].val) Del(tree[o].son[0],x);
    else Del(tree[o].son[1],x);
}

void find(QAQ o,QAQ x){
    if(!o) return ;
    if(tree[o].val>=x&&tree[o].val<t) t=tree[o].val;
    if(tree[o].val<=x&&tree[o].val>s) s=tree[o].val;
    if(tree[o].val>x) find(tree[o].son[0],x);
    if(tree[o].val<x) find(tree[o].son[1],x);
}

QAQ main(){
    scanf("%d%d",&n,&m);
    srand(n);
    while(m--){
        char c;
        QAQ x;
        cin>>c;
        if(c=='D'){
            scanf("%d",&x);
            Insert(rot,x);
            sta[++tot]=x;
        }
        else if(c=='R'){
            Del(rot,sta[tot--]);
        }
        else {
            scanf("%d",&x);
            s=0;t=n+1;
            find(rot,x);
            printf(s==t ? "0\n" : "%d\n",t-s-1);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/heower/p/8463388.html