treap数组版

然而就是将指针的地方换成int引用

就是存个代码

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
struct node
{
    int val;
    int yuk;
    int siz;
    int key;
    int ch[2];
};
node t[501000];
int tail;
int cmp(int now,int val)
{
    if(t[now].val==val) return -1;
    return t[now].val > val ? 0 : 1 ;
}
void sum(int &now)
{
    t[now].siz=t[t[now].ch[0]].siz+t[t[now].ch[1]].siz+t[now].yuk;
    return ;
}
void rotato(int &now,int base)
{
    int k=t[now].ch[base^1];
    t[now].ch[base^1]=t[k].ch[base];
    t[k].ch[base]=now;
    sum(now);   sum(k);
    now=k;
}
int New(int val)
{
    ++tail;
    t[tail].ch[0]=t[tail].ch[1]=0;
    t[tail].siz=1;t[tail].yuk=1;
    t[tail].val=val;
    t[tail].key=rand();
    return tail;
}
void init()
{
    t[0].val=0;t[0].yuk=0;
    t[0].key=-1;
    t[0].ch[0]=t[0].ch[1]=0;
    srand(time(NULL));
    return ;
}
void insert(int &now,int val)
{
    if(now==0){now=New(val);return ;}
    int dir=cmp(now,val);
    if(dir==-1){t[now].yuk+=1;t[now].siz+=1;return ;}
    insert(t[now].ch[dir],val);
    if(t[t[now].ch[dir]].key>t[now].key)    rotato(now,dir^1);
    sum(now);
}
void del(int &now,int val)
{
    int dir=cmp(now,val);
    if(dir==-1)
        if(t[now].yuk>1){t[now].siz-=1,t[now].yuk-=1;return;}
        else
        {
            if(t[now].ch[1]&&t[now].ch[0])
            {
                int nxt= t[t[now].ch[0]].key > t[t[now].ch[1]].key ? 0 : 1;
                rotato(now,nxt^1);
                del(t[now].ch[nxt^1],val);
                sum(now);return ;
            }
            if(t[now].ch[1]){now=t[now].ch[1];sum(now);return ;}
            else {now=t[now].ch[0];sum(now);return ;}
        }
    del(t[now].ch[dir],val);sum(now);
    return;
}
int nxt(int now,int val)
{
    if(!now)    return 0x7fffffff;
    if(t[now].val>val)
        return min(t[now].val,nxt(t[now].ch[0],val));
    else
        return nxt(t[now].ch[1],val);
}
int pre(int now,int val)
{
    if(!now)    return -0x7fffffff;
    if(t[now].val<val)
        return max(t[now].val,pre(t[now].ch[1],val));
    else    
        return pre(t[now].ch[0],val);
}
int find(int &now,int val)
{
    int dir=cmp(now,val);
    if(dir==-1) return t[t[now].ch[0]].siz+1;
    return find(t[now].ch[dir],val) + ( dir ? t[t[now].ch[0]].siz + t[now].yuk : 0);
}
int kth(int &now,int k)
{
    if(t[t[now].ch[0]].siz<k&&t[t[now].ch[0]].siz+t[now].yuk>=k)
        return t[now].val;
    if(k<=t[t[now].ch[0]].siz)
        return kth(t[now].ch[0],k);
    else
        return kth(t[now].ch[1],k-t[t[now].ch[0]].siz-t[now].yuk);
}
int root;
void visit(int now)
{
    if(!now)
        return ;
    visit(t[now].ch[0]);
    printf("%d ",t[now].val);
    visit(t[now].ch[1]);
    return ;
}
int main()
{
    int n;
    scanf("%d",&n);
    int a,b;
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&a,&b);
        switch(a)
        {
            case 1:insert(root,b);break;
            case 2:del(root,b);break;
            case 3:printf("%d\n",find(root,b));break;
            case 4:printf("%d\n",kth(root,b));break;
            case 5:insert(root,b);printf("%d\n",pre(root,b));del(root,b);break;
            case 6:insert(root,b);printf("%d\n",nxt(root,b));del(root,b);break;
        }
        //visit(root);printf("\n");
    }
}

转载于:https://www.cnblogs.com/Lance1ot/p/9164293.html

### 关于 Treap 数据结构的学习笔记与资料 Treap 是一种结合了二叉搜索树 (BST) 和堆特性的平衡树数据结构,能够高效地完成动态集合上的各种操作,例如插入、删除、查找等[^1]。它的核心思想在于通过引入随机优先级来维持树的平衡性,从而避免传统二叉搜索树可能退化为链表的情况。 #### Treap 的特性 Treap 同样具备 AVL 树的功能,但在实现方式上有所不同。它利用随机化的优先级替代复杂的旋转机制,使得其实现更加简洁且性能更优[^2]。具体来说,Treap 可以用于解决以下问题: - 单点查询、修改和删除。 - 动态维护序列中的排名信息及其对应的值。 - 支持区间操作(当与其他高级技巧如树套树结合时)。 以下是有关 Treap 学习的一些重要知识点: --- #### 一、Treap 的基本概念 Treap 结合了两种经典数据结构的特点: 1. **二叉搜索树 (Binary Search Tree)**:对于任意节点 \( u \),左子树的所有键值小于等于 \( u.val \),右子树的所有键值大于等于 \( u.val \)[^4]。 2. **堆性质 (Heap Property)**:每个节点的优先级都高于其左右子节点的优先级。这里的优先级通常由随机数生成器决定[^3]。 这种双重约束确保了 Treap 在平均情况下的高度接近对数级别,从而实现了高效的插入、删除和查询操作。 --- #### 二、Treap 的实现细节 为了便于理解,下面提供了一个简单的 C++ 实现框架,展示了如何定义 Treap 节点并执行分裂 (`split`) 和合并 (`merge`) 操作。 ```cpp struct Node { int key; // 键值 int priority; // 随机优先级 int size; // 当前子树大小 Node* left; Node* right; Node(int k, int p) : key(k), priority(p), size(1), left(nullptr), right(nullptr) {} }; // 计算当前节点的子树大小 int getSize(Node* root) { return root ? root->size : 0; } // 更新节点的子树大小 void updateSize(Node* node) { if (node) node->size = getSize(node->left) + getSize(node->right) + 1; } // 合并两棵 Treap Node* merge(Node* l, Node* r) { if (!l || !r) return l ? l : r; if (l->priority > r->priority) { l->right = merge(l->right, r); updateSize(l); return l; } else { r->left = merge(l, r->left); updateSize(r); return r; } } ``` 上述代码片段中包含了 `merge` 函数的核心逻辑,它是构建其他功能的基础之一[^3]。 --- #### 三、常见应用案例 1. **单点更新与查询** 使用 Treap 维护一个动态数组,支持快速定位某个位置处的数值或者统计某范围内满足条件的数量[^1]。 2. **顺序统计** 如果需要频繁访问第 K 小/大的元素,则可以通过调整结点存储的信息轻松扩展标准本的 Treap 来适应此类需求[^4]。 3. **区间覆盖标记优化** 对于一些涉及大量重复写入的任务场景,可以考虑采用懒惰传播技术进一步提升效率[^2]。 --- #### 四、注意事项 尽管 Treap 提供了一种优雅的方式来管理动态集合作业,但也需要注意以下几个方面: - 若输入分布具有特殊模式可能导致最坏情况下时间复杂度恶化至线性阶次; - 编程竞赛环境下由于内存分配开销较大建议预先申请固定容量空间而非实时创建新对象实例; --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值