洛谷-3380 【模板】二逼平衡树(树套树)

本文介绍了一种结合Treap与线段树的数据结构,用于高效处理区间查询与更新操作,包括查询数值排名、查找特定排名的数值、修改数值、寻找前驱与后继等。通过这种数据结构,可以实现在大规模数据集上快速响应各种查询需求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
查询k在区间内的排名
查询区间内排名为k的值
修改某一位值上的数值
查询k在区间内的前驱(前驱定义为严格小于x,且最大的数,若不存在输出-2147483647)
查询k在区间内的后继(后继定义为严格大于x,且最小的数,若不存在输出2147483647)
#注意上面两条要求和tyvj或者bzoj不一样,请注意
输入格式
第一行两个数 n,m 表示长度为n的有序序列和m个操作
第二行有n个数,表示有序序列
下面有m行,opt表示操作标号
若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r]的排名
若opt=2 则为操作2,之后有三个数l,r,k 表示查询区间[l,r]内排名为k的数
若opt=3 则为操作3,之后有两个数pos,k 表示将pos位置的数修改为k
若opt=4 则为操作4,之后有三个数l,r,k 表示查询区间[l,r]内k的前驱
若opt=5 则为操作5,之后有三个数l,r,k 表示查询区间[l,r]内k的后继
输出格式
对于操作1,2,4,5各输出一行,表示查询结果

输入输出样例
输入 #1
9 6
4 2 2 1 9 4 0 1 1
2 1 4 3
3 4 10
2 1 4 3
1 2 5 9
4 3 9 5
5 2 8 5

输出 #1
2
4
3
4
9

说明/提示
时空限制:2s,128M
n,m≤5⋅104n,m≤5⋅10^4n,m5104保证有序序列所有值在任何时刻满足 [0,108][0,10^8][0,108]

#include <algorithm>
#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include <complex>
#include <string>
#include <cstdio>
#include <vector>
#include <bitset>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <map>
#include <set>
using namespace std;
const int MAXN = 1e5 + 100;
int n, m;
int a[MAXN];
namespace Treap{
    struct balanced{
        int w;
        int sz;
        int num;
        int fix;
        int ch[2];
    };
    int tot;
    balanced tree[MAXN * 20];
    int newnode(int w){
        ++tot;
        tree[tot].w = w;
        tree[tot].fix = rand();
        tree[tot].num = 1;
        tree[tot].ch[0] = tree[tot].ch[1] = 0;
        tree[tot].sz = 1;
        return tot;
    }
    void pushup(int p){
        tree[p].sz = tree[tree[p].ch[0]].sz + tree[tree[p].ch[1]].sz + tree[p].num;
    }
    void rotate(int &p, int d){
        int y = tree[p].ch[d];
        tree[p].ch[d] = tree[y].ch[d ^ 1];
        tree[y].ch[d ^ 1] = p;
        pushup(p);
        pushup(y);
        p = y;
    }
    void insert(int &p, int w){
        if (!p) p = newnode(w);
        else if (tree[p].w == w) ++tree[p].num;
        else{if (tree[p].w > w){
                insert(tree[p].ch[0], w);
                if(tree[tree[p].ch[0]].fix > tree[p].fix) rotate(p, 0);
            }
            else{
                insert(tree[p].ch[1], w);
                if (tree[tree[p].ch[1]].fix > tree[p].fix) rotate(p, 1);
            }
        }
        pushup(p);
    }
    void remove(int &p, int w){
        if (tree[p].w > w) remove(tree[p].ch[0], w);
        else if (tree[p].w < w) remove(tree[p].ch[1], w);
        else{
            if (tree[p].num > 1) --tree[p].num;
            else{
                if (!tree[p].ch[0] && !tree[p].ch[1]) p = 0;
                else if (!tree[p].ch[0]){
                    rotate(p, 1);
                    remove(tree[p].ch[0], w);
                }
                else if (!tree[p].ch[1]){
                    rotate(p, 0);
                    remove(tree[p].ch[1], w);
                }
                else{
                    if (tree[tree[p].ch[0]].fix > tree[tree[p].ch[1]].fix){
                        rotate(p, 0);
                        remove(tree[p].ch[1], w);
                    }
                    else{
                        rotate(p, 1);
                        remove(tree[p].ch[0], w);
                    }
                }
            }
        }
        if (p) pushup(p);
    }
    int queryrank(int p, int k){
        if (!p) return 0;
        if (tree[p].w > k) return queryrank(tree[p].ch[0], k);
        else if (tree[p].w == k) return tree[tree[p].ch[0]].sz;
        else return tree[tree[p].ch[0]].sz + tree[p].num + queryrank(tree[p].ch[1], k);
    }
    int querynum(int p, int k){
        if (tree[tree[p].ch[0]].sz + 1 == k) return tree[p].w;
        else if (tree[tree[p].ch[0]].sz + 1 < k) return querynum(tree[p].ch[1], k - 1 - tree[tree[p].ch[0]].sz);
        else     return querynum(tree[p].ch[0], k);
    }
    int querypre(int p, int k){
        if (!p)  return -2147483647;
        if (tree[p].w >= k) return querypre(tree[p].ch[0], k);
        else return max(tree[p].w, querypre(tree[p].ch[1], k));
    }
    int querysuf(int p, int k){
        if (!p) return 2147483647;
        if (tree[p].w <= k) return querysuf(tree[p].ch[1], k);
        else return min(tree[p].w, querysuf(tree[p].ch[0], k));
    }
    void listall(int p){
        if (tree[p].ch[0]) listall(tree[p].ch[0]);
        cerr << tree[p].w << ",sz=" << tree[p].num << "   ";
        if (tree[p].ch[1]) listall(tree[p].ch[1]);
    }
}
using Treap::listall;
namespace SEG{
    struct segment{
        int l;
        int r;
        int root;
    };
    segment tree[MAXN * 8];
    void build(int p, int l, int r){
        tree[p].l = l;
        tree[p].r = r;
        for (int i = l; i < r + 1; ++i) Treap::insert(tree[p].root, a[i]);
        if (l != r){
            int mid = (l + r) / 2;
            build(p * 2, l, mid);
            build(p * 2 + 1, mid + 1, r);
        }
    }
    void modify(int p, int x, int y){
        Treap::remove(tree[p].root, a[x]);
        Treap::insert(tree[p].root, y);
        if (tree[p].l == tree[p].r) return;
        int mid = (tree[p].l + tree[p].r) / 2;
        if (x > mid) modify(p * 2 + 1, x, y);
        else modify(p * 2, x, y);
    }
    int queryrank(int p, int l, int r, int k){
        if (tree[p].l > r || tree[p].r < l) return 0;
        if (tree[p].l >= l && tree[p].r <= r) return Treap::queryrank(tree[p].root, k);
        else return queryrank(p * 2, l, r, k) + queryrank(p * 2 + 1, l, r, k);
    }
    int querynum(int u, int v, int k){
        int l = 0, r = 1e8;
        while (l < r){
            int mid = (l + r + 1) / 2;
            if (queryrank(1, u, v, mid) < k) l = mid;
            else r = mid - 1;
        }
        return r;
    }
    int querypre(int p, int l, int r, int k){
        if (tree[p].l > r || tree[p].r < l) return -2147483647;
        if (tree[p].l >= l && tree[p].r <= r) return Treap::querypre(tree[p].root, k);
        else return max(querypre(p * 2, l, r, k), querypre(p * 2 + 1, l, r, k));
    }
    int querysuf(int p, int l, int r, int k){
        if (tree[p].l > r || tree[p].r < l) return 2147483647;
        if (tree[p].l >= l && tree[p].r <= r) return Treap::querysuf(tree[p].root, k);
        else return min(querysuf(p * 2, l, r, k), querysuf(p * 2 + 1, l, r, k));
    }
}
int read(){
    char ch = getchar();
    int x = 0, flag = 1;
    while (ch != '-' && (ch < '0' || ch > '9'))
        ch = getchar();
    if (ch == '-'){
        ch = getchar();
        flag = -1;
    }
    while (ch >= '0' && ch <= '9'){
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * flag;
}
int main(){
    n = read();
    m = read();
    for (int i = 1; i < n + 1; ++i) a[i] = read();
    SEG::build(1, 1, n);
    for (int i = 0; i < m; ++i){
        int opt = read();
        if (opt == 3){
            int x = read(), y = read();
            SEG::modify(1, x, y);
            a[x] = y;
        }
        else{
            int l = read(), r = read(), k = read();
            if (opt == 1) printf("%d\n", SEG::queryrank(1, l, r, k) + 1);
            else if (opt == 2) printf("%d\n", SEG::querynum(l, r, k));
            else if (opt == 4) printf("%d\n", SEG::querypre(1, l, r, k));
            else printf("%d\n", SEG::querysuf(1, l, r, k));
        }
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值