FHQ-Treap 树 ← 洛谷P3369、AcWing253

【题目来源】
https://www.luogu.com.cn/problem/P3369
https://www.acwing.com/problem/content/255/

【题目描述】
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入数值 x。
2. 删除数值 x(若有多个相同的数,应只删除一个)。
3. 查询数值 x 的排名(若有多个相同的数,应输出最小的排名)。
4. 查询排名为 x 的数值。
5. 求数值 x 的前驱(前驱定义为小于 x 的最大的数)。
6. 求数值 x 的后继(后继定义为大于 x 的最小的数)。
注意: 数据保证查询的结果一定存在。

【输入格式】
第一行为 n,表示操作的个数。
接下来 n 行每行有两个数 opt 和 x,opt 表示操作的序号(1≤opt≤6)。

【输出格式】
对于操作 3,4,5,6 每行输出一个数,表示对应答案。

【数据范围】
1≤n≤100000,所有数均在 −10^7 到 10^7 内。

【输入样例】
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

【输出样例】
106465
84185
492737

【算法分析】
● FHQ−Treap,也称非旋 Treap,由范浩强提出。顾名思义,FHQ−Treap 就是不需要通过旋转,而是通过分裂(split)与合并(merge)维护的 Treap。FHQ−Treap 与 Treap 的另外一个区别是 FHQ−Treap 可持久化。
● FHQ-Treap 的高明之处在于所有的操作都只用到了分裂(split)与合并(merge)这两个基本操作。
● 本题的 Treap 树实现参见:https://blog.csdn.net/hnjzsyjyj/article/details/138482439
● 本题的替罪羊树实现参见:https://blog.csdn.net/hnjzsyjyj/article/details/128647972

【算法代码】

#include <bits/stdc++.h>
using namespace std;

const int maxn=5e5+5;
int ch[maxn][2]; //left son, right son
int val[maxn],pri[maxn],cnt[maxn],id;

void update(int x) {
    cnt[x]=1+cnt[ch[x][0]]+cnt[ch[x][1]];
}

int new_node(int v) {
    cnt[++id]=1;
    val[id]=v;
    pri[id]=rand();
    return id;
}

int merge(int x,int y) {
    if(!x || !y) return x+y;
    if(pri[x]<pri[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;
    }
}

void split(int cur,int k,int &x,int &y) {
    if(!cur) x=y=0;
    else {
        if(val[cur]<=k) x=cur,split(ch[cur][1],k,ch[cur][1],y);
        else y=cur,split(ch[cur][0],k,x,ch[cur][0]);
        update(cur);
    }
}

int kth(int cur,int k) {
    while(1) {
        if(k<=cnt[ch[cur][0]]) cur=ch[cur][0];
        else if(k==cnt[ch[cur][0]]+1) return cur;
        else k-=cnt[ch[cur][0]]+1,cur=ch[cur][1];
    }
}

int main() {
    int T,opt,x,y,z,a,b,root=0;
    scanf("%d",&T);
    while(T--) {
        scanf("%d%d",&opt,&a);
        if(opt==1) {
            split(root,a,x,y);
            root=merge(merge(x,new_node(a)),y);
        } else if(opt==2) {
            split(root,a,x,z);
            split(x,a-1,x,y);
            y=merge(ch[y][0],ch[y][1]);
            root=merge(merge(x,y),z);
        } else if(opt==3) {
            split(root,a-1,x,y);
            printf("%d\n",cnt[x]+1);
            root=merge(x,y);
        } else if(opt==4)
            printf("%d\n",val[kth(root,a)]);
        else if(opt==5) {
            split(root,a-1,x,y);
            printf("%d\n",val[kth(x,cnt[x])]);
            root=merge(x,y);
        } else {
            split(root,a,x,y);
            printf("%d\n",val[kth(y,1)]);
            root=merge(x,y);
        }
    }

    return 0;
}

/*
in:
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598

out:
106465
84185
492737
*/



【参考文献】
https://www.luogu.com.cn/blog/85514/fhq-treap-xue-xi-bi-ji
https://blog.csdn.net/m0_51796369/article/details/119834710
http://www.yhzq-blog.cc/fhq-treap%E6%80%BB%E7%BB%93/
https://www.luogu.com.cn/problem/P3369
https://www.acwing.com/problem/content/255/
https://www.acwing.com/blog/content/4455/
https://www.acwing.com/problem/content/description/268/
https://blog.csdn.net/weixin_44316314/article/details/114155492



 

posted @ 2026-01-27 09:03  Triwa  阅读(3)  评论(0)    收藏  举报