二逼平衡树(树套树)

本文介绍了如何使用平衡树解决数据结构问题,特别是BZOJ-3196中的“二逼平衡树”挑战。通过结合线段树和Treap(或Splay树)的数据结构,实现对有序序列的一系列操作,如查询排名、修改值、查找前驱和后继。重点讲述了操作2的二分查找策略,并建议使用类来封装数据结构和操作。
摘要由CSDN通过智能技术生成

二逼平衡树(树套树)

二逼平衡树是[平衡树三题]里的最后一题,或许是因为比较恶心,所以叫它二逼吧(你看文艺平衡树多好听(●ˇ∀ˇ●)),其实想想还是比较好写的。。。还有,我管它叫Segment Treap(●’◡’●)

目录

题目

BZOJ-3196 [平衡树三题]二逼平衡树

您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:

1.查询k在区间内的排名
2.查询区间内排名为k的值
3.修改某一位值上的数值
4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)
5.查询k在区间内的后继(后继定义为大于x,且最小的数)

思路

  1. 由于这些操作都是查排名之类的,首先会想到核心内容必定是由平衡树来完成;
  2. 再看题,都是区间的操作,所以想到外层应该是线段树,其实正解即如此!
  3. 大体上,就是先是线段树维护每个区间,之后线段树每个节点都是一个treap来维护(用treap主要是splay 常数太大,容易TLE)。这里要注意,虽然每个线段树节点都是treap,但不需要每个treap都开很大的节点数,实际上treap总结点数只需2nlogn个;
  4. 操作1、3、4、5都很好写,就是先像普通的线段树一样,递归的找到操作区间的子区间,之后对该区间对应的treap操作即可;
  5. 难点主要是操作2,其实做法是二分答案,二分一个值然后看在查询区间里的排名。

代码

强烈推荐使用class封装

#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;

const int MAXN=100005,INF=~0U>>1,MAX=int(1e8),MIN=-MAX;
int cnt,n,m;
int tmp[MAXN];

struct node{
    int s[2],fa,w,val,sz,cnt;
}d[1500005];

class treap{
    private:
        int sz,rt;
        void sgl_upd(int u){
            d[u].sz=d[u].cnt+d[d[u].s[0]].sz+d[d[u].s[1]].sz;
        }
        void path_upd(int u){
            while(u){
                sgl_upd(u);
                u=d[u].fa;
            }
        }
        void rot(int u){
            int ufa=d[u].fa;
            bool lr= d[ufa].s[1]==u;
            d[u].fa=d[ufa].fa;
            if(d[ufa].fa)
                d[d[ufa].fa].s[d[d[ufa].fa].s[1]==ufa]=u;
            else rt=u;
            d[ufa].s[lr]=d[u].s[lr^1];
            d[d[ufa].s[lr]].fa=ufa;
            d[u].s[lr^1]=ufa;
            d[ufa].fa=u;
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值