treap模板

旋转版treap:
//1. 插入x数
//2. 删除x数(若有多个相同的数,因只删除一个)
//3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
//4. 查询排名为x的数
//5. 求x的前驱(前驱定义为小于x,且最大的数)
//6. 求x的后继(后继定义为大于x,且最小的数)
const int N = 100000 + 10, INF = 2e9 + 10;

struct node
{
    int val, pri, son[2];
    int sz, num;
    void init(int _val, int _pri, int _sz, int _num)
    {
        val = _val, pri = _pri, sz = _sz, num = _num;
        son[0] = son[1] = 0;
    }
}tr[N];
int tot, root;
void init()
{
    tot = 0, root = 0;
    tr[0].init(0, 0, 0, 0);
}
void update(int x)
{
    tr[x].sz = tr[tr[x].son[0]].sz + tr[tr[x].son[1]].sz + tr[x].num;
}
void Rotate(int &x, int p)//p=0左旋,p=1右旋
{
    int y = tr[x].son[!p];
    tr[x].son[!p] = tr[y].son[p];
    tr[y].son[p] = x;
    update(x); update(y);//必须先更新x后更新y
    x = y;
}
void Insert(int &x, int val)
{
    if(x == 0) tr[x = ++tot].init(val, rand(), 1, 1);
    else
    {
        tr[x].sz++;
        if(tr[x].val == val)
        {
            tr[x].num++;
            return;
        }
        int p = val > tr[x].val;
        Insert(tr[x].son[p], val);
        if(tr[x].pri < tr[tr[x].son[p]].pri) Rotate(x, !p);
    }
}
void del(int &x, int val)
{//删除之前可以先查看一下这个值是否存在
    //if(x == 0) return;
    if(tr[x].val == val)
    {
        if(tr[x].num > 1)
        {
            tr[x].sz--;
            tr[x].num--;
            return;
        }
        if(tr[x].son[0] && tr[x].son[1])
        {
            int p = tr[tr[x].son[0]].pri > tr[tr[x].son[1]].pri;
            Rotate(x, p);
            tr[x].sz--;//如果接下删除tr[x].son[p],注意处理tr[x].sz,因为这个一直TLE
            del(tr[x].son[p], val);
            //del(x, val); //注释掉的写法不用处理sz的问题,因为递归到下一层会处理
        }
        else
        {
            //x = tr[x].son[0] + tr[x].son[1];  //合并,很凝炼
            if(tr[x].son[0] != 0) x = tr[x].son[0];
            else x = tr[x].son[1];
        }
    }
    else
    {
        int p = val > tr[x].val;
        tr[x].sz--;
        del(tr[x].son[p], val);
    }
}
int get_kth(int x, int k)
{
    //if(x == 0) return 0;
    if(k > tr[tr[x].son[0]].sz + tr[x].num) return get_kth(tr[x].son[1], k - tr[tr[x].son[0]].sz - tr[x].num);
    else if(k <= tr[tr[x].son[0]].sz) return get_kth(tr[x].son[0], k);
    else return tr[x].val;
}
int get_rank(int x, int val)
{
    //if(x == 0) return 0;
    if(val == tr[x].val) return tr[tr[x].son[0]].sz + 1;
    else if(val > tr[x].val) return get_rank(tr[x].son[1], val) + tr[tr[x].son[0]].sz + tr[x].num;
    else return get_rank(tr[x].son[0], val);
}
//求前驱和后继用两种不同的方法,其实一种即可
int get_prec(int x, int val)
{
    int ans = -INF;
    while(x)
    {
        if(val <= tr[x].val) x = tr[x].son[0];
        else ans = max(ans, tr[x].val), x = tr[x].son[1];
    }
    return ans;
}
int get_succ(int x, int val)
{
    if(! x) return INF;
    if(val >= tr[x].val) return get_succ(tr[x].son[1], val);
    else return min(tr[x].val, get_succ(tr[x].son[0], val));
}
int main()
{
    int n, op, val;
    scanf("%d", &n);
    init();
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d", &op, &val);
        if(op == 1) Insert(root, val);
        else if(op == 2) del(root, val);
        else if(op == 3) printf("%d\n", get_rank(root, val));
        else if(op == 4) printf("%d\n", get_kth(root, val));
        else if(op == 5) printf("%d\n", get_prec(root, val));
        else if(op == 6) printf("%d\n", get_succ(root, val));
    }
    return 0;
}

非旋转版treap

typedef pair<int, int> proot;
const int N = 100000 + 10, INF = 2e9 + 10;
struct node
{
    int l, r, val, pri, sz;
    void init(int _val, int _pri, int _sz)
    {
        val = _val, pri = _pri, sz = _sz;
        l = r = 0;
    }
}tr[N];
int root, tot;
void init()
{
    root = 0, tot = 0;
    tr[0].init(0, 0, 0);
}
int new_node(int val)
{
    tr[++tot].init(val, rand(), 1);
    return tot;
}
void update(int x)
{
    tr[x].sz = 1 + tr[tr[x].l].sz + tr[tr[x].r].sz;
}
proot split(int x, int k)//把树x分裂成两个树,前k个元素一个数,剩余的元素一个树
{
    if(! k) return proot(0, x);
    proot y;
    if(tr[tr[x].l].sz >= k)
    {
        y = split(tr[x].l, k);
        tr[x].l = y.second;
        update(x);
        y.second = x;
    }
    else
    {
        y = split(tr[x].r, k - tr[tr[x].l].sz - 1);
        tr[x].r = y.first;
        update(x);
        y.first = x;
    }
    return y;
}
int Merge(int x, int y)//把树x,y合并成一棵,并返回树根
{
    if(!x || !y) return x + y;
    if(tr[x].pri < tr[y].pri)
    {
        tr[x].r = Merge(tr[x].r, y);
        update(x);
        return x;
    }
    else
    {
        tr[y].l = Merge(x, tr[y].l);
        update(y);
        return y;
    }
}
bool Find(int x, int val)
{
    if(!x) return false;
    if(val == tr[x].val) return true;
    else if(val < tr[x].val) return Find(tr[x].l, val);
    else return Find(tr[x].r, val);
}
//int get_rank(int x, int val)//树中无重复值才能用这个
//{
//    if(!x) return 0;
//    if(val == tr[x].val) return tr[tr[x].l].sz + 1;
//    else if(val < tr[x].val) return get_rank(tr[x].l, val);
//    else return tr[tr[x].l].sz + 1 + get_rank(tr[x].r, val);
//}
int get_rank(int x, int val)//排名为get_rank()+1
{
    if(!x) return 0;
    return val <= tr[x].val ? get_rank(tr[x].l, val) : get_rank(tr[x].r, val) + tr[tr[x].l].sz + 1;
}
int get_kth(int x, int k)
{
    if(tr[tr[x].l].sz + 1 == k) return tr[x].val;
    else if(k <= tr[tr[x].l].sz) return get_kth(tr[x].l, k);
    else return get_kth(tr[x].r, k - tr[tr[x].l].sz - 1);
}
void Insert(int val)
{//插入元素。首先确定新元素的排名,然后依据这个排名把树分裂成两个,然后把新元素夹在两个树中间,合并
    int k = get_rank(root, val);
    proot x = split(root, k);
    int y = new_node(val);
    root = Merge(Merge(x.first, y), x.second);
}
void del(int val)
{//删除元素。首先确定元素排名k,然后前k-1个分裂成一个树,剩余的元素再进行一次分裂,把第一个也就是待删除元素单独分裂出来,然后合并即可
    int k = get_rank(root, val) + 1;
    proot x = split(root, k-1);
    proot y = split(x.second, 1);
    root = Merge(x.first, y.second);
}
//int get_prec(int x, int val)
//{
//    int ans = -INF;
//    while(x)
//    {
//        if(val <= tr[x].val) x = tr[x].l;
//        else ans = max(ans, tr[x].val), x = tr[x].r;
//    }
//    return ans;
//}
//int get_succ(int x, int val)
//{
//    if(! x) return INF;
//    if(val >= tr[x].val) return get_succ(tr[x].r, val);
//    else return min(tr[x].val, get_succ(tr[x].l, val));
//}
int get_prec(int root, int val)
{
    int k = get_rank(root, val);
    proot x = split(root, k-1);
    proot y = split(x.second, 1);
    int ans = tr[y.first].val;
    root = Merge(Merge(x.first, y.first), y.second);
    return ans;
}
int get_succ(int root, int val)
{
    int k = get_rank(root, val+1);
    proot x = split(root, k);
    proot y = split(x.second, 1);
    int ans = tr[y.first].val;
    root = Merge(Merge(x.first, y.first), y.second);
    return ans;
}
int main()
{
    int n, op, val;
    scanf("%d", &n);
    init();
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d", &op, &val);
        if(op == 1) Insert(val);
        else if(op == 2) del(val);
        else if(op == 3) printf("%d\n", get_rank(root, val) + 1);
        else if(op == 4) printf("%d\n", get_kth(root, val));
        else if(op == 5) printf("%d\n", get_prec(root, val));
        else if(op == 6) printf("%d\n", get_succ(root, val));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值