静态主席树结点版本.java 3.6 KB
Newer Older
qq_36480062's avatar
c  
qq_36480062 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
package 线段树;

import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;

import static java.lang.System.in;

/**
 * 不能用废弃
 * https://www.acwing.com/blog/content/487/
 * 静态区间第k大
 * 我们可以建立一颗权值线段树,每个点存储的信息为该值域区间存在的数的个数。
 */
public class 静态主席树结点版本 {
    static BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
    static BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    static StringTokenizer tokenizer = new StringTokenizer("");

    static String nextLine() throws IOException {// 读取下一行字符串
        return reader.readLine();
    }

    static String next() throws IOException {// 读取下一个字符串
        while (!tokenizer.hasMoreTokens()) {
            //如果没有字符了,就是下一个,使用空格拆分,
            tokenizer = new StringTokenizer(reader.readLine());
        }
        return tokenizer.nextToken();
    }

    static int nextInt() throws IOException {// 读取下一个int型数值
        return Integer.parseInt(next());
    }

    static double nextDouble() throws IOException {// 读取下一个double型数值
        return Double.parseDouble(next());
    }

    static class seg {
        int l, r, v;

        public seg(int l, int r, int v) {
            this.l = l;
            this.r = r;
            this.v = v;
        }
    }

    static seg[] tr = new seg[200100 * 20];

    public static void main(String[] args) throws IOException {
        n = nextInt();
        m = nextInt();
        for (int i = 1; i <= n; i++) {
            a[i] = nextInt();
            d[i] = a[i];
        }
        Arrays.sort(d, 1, n + 1);
        int len = unique(d, n);
        for (int i = 1; i <= n; i++) {
            a[i] = Arrays.binarySearch(d, 1, 1 + len, a[i]);
        }
        T[0] = build(1, len);
        int l, r, k;
        while (m-- != 0) {
            l = nextInt();
            r = nextInt();
            k = nextInt();
            int ans = query(T[l - 1], T[r], l, len, k);
            bw.write(d[ans] + "\n");
        }
        bw.flush();
    }

    static int[] a = new int[200010];
    static int[] d = new int[200010];
    static int[] T = new int[200010];
    static int tot = 0, n, m;

    static int unique(int[] t, int n) {
        int j = 1;
        for (int i = 1; i <= n; i++) {
            if (j == 1 || t[i] != t[i - 1]) {
                t[j++] = t[i];
            }
        }
        return j;
    }

    /**
     * 建树,
     *
     * @param l 左区间
     * @param r
     * @return 根节点位置
     */
    static int build(int l, int r) {
        int p = ++tot, mid = l + r >> 1;
        tr[p] = new seg(l, r, 0);
        if (l < r) {
            tr[p].l = build(l, mid);
            tr[p].r = build(mid + 1, r);
        }
        return p;
    }

    static int update(int pre, int l, int r, int v) {
        int p = ++tot, mid = l + r >> 1;
        tr[p].l = tr[pre].l;
        tr[p].r = tr[pre].r;
        tr[p].v = tr[pre].v + 1;
        if (l < r) {
            //应该更新哪一个值域区间
            if (v <= mid) tr[p].l = update(tr[pre].l, l, mid, v);
            else tr[p].r = update(tr[pre].r, mid + 1, r, v);
        }
        return p;
    }

    static int query(int x, int y, int l, int r, int k) {
        if (l == r) return l;
        //对位相减
        int sum = tr[tr[y].l].v - tr[tr[x].l].v, mid = l + r >> 1;
        if (k <= sum) return query(tr[x].l, tr[y].l, l, mid, k);
        else return query(tr[x].r, tr[y].r, mid + 1, r, k - sum);
    }

}