首页 > 其他 > 详细

fhq-treap

时间:2020-01-17 23:32:47      阅读:76      评论:0      收藏:0      [点我收藏+]

\(fhq-treap\)

复习一下fhq-treap

fhp-treap 就是一种不旋转的treap,所以也就有treap的性质——BST + 堆,然后用拆分+合并代替treap的旋转操作

其优点在于:

支持区间,效率高,可持久化

下面是需要的变量

val : 按树的平衡权值
key : 按堆的权值
sz  : 子树大小
rt  : 当前根
ch[now][0] : 左儿子  ch[now][1] 右儿子
#define ls ch[now][0]
#define rs ch]now][1]

操作一 : split(拆树

将一棵树拆成两个

void split(int now,int k,int &x,int &y) //x <= k,y > k
{
    if(!now) {
        x = y = 0;
        return;
    }
    if(val[now] <= k) x = now,split(rs,k,rs,y);
    else y = now,split(ls,k,x,ls);
    update(now);
}

? 函数意义是:以now为根,将树拆成两部分,x部的权值全部 \(\leq\) k, y部全 > k

考虑当前节点now:

  • 如果val[now] \(\leq\) k:

    ? 那么now的左子树应当被分给x(较为显然QwQ),而now的右子树不确定,同时x的右子树也不确定,而y未被分配,因此进入下一层求解。

  • val[now] > k 同理

操作二 merge(合并

将两个树合并,返回新树的根:

int merge(int x,int y)//val:x <= y 
{
    if(!x || !y) return x + y;
    if(key[x] < key[y]){
        ch[x][1] = merge(ch[x][1],y);
        update(x);
        return x;
    }
    else {
        ch[y][0] = merge(x,ch[y][0]);
        update(y);
        return y;
    }
}

规定:val[x] < val[y]

如果x和y中有一个为空,那么返回另一个即可

由于x,y是由split得来的,因此二者均是bst,因此在合并时,只需要考虑堆的性质即可

然后剩下的操作就围绕着这两个操作展开

** 新建点:这个不用多说,与treap一样 **

int New(int k){
    key[++tot] = rand(),val[tot] = k,sz[tot] = 1;
    return tot;
}

插入一个数k:

? 先把树按照k拆成两份(x,y),把k加到x中,再把树合并回去

void insert(int k){
    int x,y;
    split(root,k,x,y);
    root = merge(merge(x,New(k)),y);
}

删除一个数k:

? 先把树按k拆分成两份(x,y),这时x中所有的数都\(\leq\)k,再将x按k - 1拆分成x和z,这时z中所有的数都等于k,删去z的根,就把z的左右儿子合并(相当于抛弃了z的根节点),然后再合并回去

void del(int k){
    int x,y,z;
    split(root,k,x,y);
    split(x,k - 1,x,z);
    z = merge(ch[z][0],ch[z][1]);
    root = merge(x,merge(z,y));
}

查k的排名:

? 把树按k - 1分成两份(注意!不能按k分,由于可能有重,按k分无法得到正解),此时x部\(\leq\) k - 1,y部 > k,输出x部的大小即可

void Rank(int k){
    int x,y;
    split(root,k - 1,x,y);
    printf("%d\n",sz[x] + 1);
    root = merge(x,y);
}

找第k大的数:

? 与treap相同,显而易见,因为有一棵平衡树。

void fRank(int now,int k){
    while(1){
        if(k <= sz[ls]) now = ls;
        else if(k > sz[ls] + 1) k -= sz[ls] + 1,now = rs;
        else { printf("%d\n",val[now]); return;}
    }
}

前后继:

由拆分和合并易得

void pre(int k){
    int x,y;
    split(root,k - 1,x,y);
    fRank(x,sz[x]);
    root = merge(x,y);
}
void suc(int k){
    int x,y;
    split(root,k,x,y);
    fRank(y,1);
    root = merge(x,y);
}

总代码放一个w

#include<cstdio>
#include<vector>
#include<cstdlib>
#include<ctime>
using namespace std;
#define ls ch[now][0]
#define rs ch[now][1]
inline int read(){
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9'){
        if(ch == '-') op = -1;
        ch = getchar();
        }
    while(ch >= '0' && ch <= '9'){
        (ans *= 10) += ch - '0';
        ch = getchar();
        }
    return ans * op;
    }
const int maxn = 1e5 + 5;
int sz[maxn],key[maxn],val[maxn],tot,ch[maxn][2],root;
inline void update(int now){
    sz[now] = sz[ls] + sz[rs] + 1;}
void split(int now,int k,int &x,int &y){
    if(!now) {        
        x = y = 0;
        return;
        }
    if(val[now] <= k) x = now,split(rs,k,rs,y);
    else y = now,split(ls,k,x,ls);
    update(now);}
int merge(int x,int y){
    if(!x || !y) return x + y;
    if(key[x] < key[y]){
        ch[x][1] = merge(ch[x][1],y);
        update(x);
        return x;
    }
    else {
        ch[y][0] = merge(x,ch[y][0]);
        update(y);
        return y;
    }
}
int New(int k){
    key[++tot] = rand(),val[tot] = k,sz[tot] = 1;
    return tot;
}
void insert(int k){
    int x,y;
    split(root,k,x,y);
    root = merge(merge(x,New(k)),y);
}
void del(int k){
    int x,y,z;
    split(root,k,x,y);
    split(x,k - 1,x,z);
    z = merge(ch[z][0],ch[z][1]);
    root = merge(x,merge(z,y));
}
void Rank(int k){
    int x,y;
    split(root,k - 1,x,y);
    printf("%d\n",sz[x] + 1);
    root = merge(x,y);
}
void fRank(int now,int k){
    while(1){
        if(k <= sz[ls]) now = ls;
        else if(k > sz[ls] + 1) k -= sz[ls] + 1,now = rs;
        else { printf("%d\n",val[now]); return;}
    }
}
void pre(int k){
    int x,y;
    split(root,k - 1,x,y);
    fRank(x,sz[x]);
    root = merge(x,y);
}
void suc(int k){
    int x,y;
    split(root,k,x,y);
    fRank(y,1);
    root = merge(x,y);
}
int main(){
    int n = read();
    int opt,x;
    while(n--){
        opt = read(),x = read(); 
        if(opt == 1) insert(x);
        if(opt == 2) del(x);
        if(opt == 3) Rank(x); 
        if(opt == 4) fRank(root,x);
        if(opt == 5) pre(x);
        if(opt == 6) suc(x); 
    }
    return 0;
}

fhq-treap

原文:https://www.cnblogs.com/excellent-zzy/p/12207475.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!