AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

[l, r]中第k小

作者: 作者的头像   不知名的fE ,  2025-05-10 12:35:55 · 河北 ,  所有人可见 ,  阅读 3


0


import java.util.*;
import java.util.stream.Collectors;

public class Main {
    static final int N = 200010;
    static Node[] tree = new Node[40 * N];
    static int[] root = new int[N], a = new int[N];
    static int n, m, idx = 0;
    static List<Integer> sorted = new ArrayList<>();

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        n = sc.nextInt();
        m = sc.nextInt();

        for (int i = 1; i <= n; i++) {
            a[i] = sc.nextInt();
            sorted.add(a[i]);
        }
        discretize(sorted);

        root[0] = build(1, sorted.size());//创建空树

        for (int i = 1; i <= n; i++) {
            int x = find(a[i]);//查找
            root[i] = update(root[i - 1], 1, sorted.size(), x, 1);//在该位置加1表示出现多1次
        }

        for (int i = 0; i < m; i++) {
            int l = sc.nextInt();
            int r = sc.nextInt();
            int k = sc.nextInt();
            /* 
                查找[l, r]第k小的数
                树种存储的是[1, i]的前缀数字出现情况
                所以需要查询[l - 1, r]的前缀数字出现情况
                上面进行离散化保证了数字的大小关系
                所以可以通过查询[1, r]的前缀数字出现情况 - [1, l - 1]的前缀数字出现情况
                得到[l, r]的前缀数字出现情况
                然后通过二分查找找到第k小的数字
            */
            System.out.println(getIndex(query(root[l - 1], root[r], 1, sorted.size(), k)));
        }
    }

    static int find(int x) {
        return Collections.binarySearch(sorted, x) + 1;
    }

    static int getIndex(int x) {
        return sorted.get(x - 1);
    }

    static void discretize(List<Integer> list) {
        List<Integer> unique = list.stream().sorted().distinct().collect(Collectors.toList());
        list.clear();
        list.addAll(unique);
    }

    static int build(int l, int r) {
        int p = ++idx;
        tree[p] = new Node();
        if (l == r) return p;
        int mid = (l + r) >> 1;
        tree[p].ls = build(l, mid);
        tree[p].rs = build(mid + 1, r);
        return p;
    }

    static int update(int pre, int l, int r, int x, int v) {
        int p = ++idx;
        if (tree[p] == null) {
            tree[p] = new Node();
            tree[p].cnt = tree[pre].cnt;
        }

        if (l == r) {
            tree[p].cnt += v;
            return p;
        }

        int mid = (l + r) >> 1;
        if (x <= mid) {
            tree[p].rs = tree[pre].rs;
            tree[p].ls = update(tree[pre].ls, l, mid, x, v);
        } else {
            tree[p].ls = tree[pre].ls;
            tree[p].rs = update(tree[pre].rs, mid + 1, r, x, v);
        }

        pushup(p);
        return p;
    }

    static void pushup(int p) {
        tree[p].cnt = tree[tree[p].ls].cnt + tree[tree[p].rs].cnt;
    }

    static int query(int pre, int now, int l, int r, int k) {
        if (l == r) return l;

        int mid = (l + r) >> 1;
        int leftCnt = tree[tree[now].ls].cnt - tree[tree[pre].ls].cnt;
        int res = 0;
        if (k <= leftCnt) {
            res = query(tree[pre].ls, tree[now].ls, l, mid, k);
        } else {
            res =  query(tree[pre].rs, tree[now].rs, mid + 1, r, k - leftCnt);
        }
        return res;
    }
}

class Node {
    int cnt;//该节点的数字出现次数
    int ls, rs;//左右子树的节点编号
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息