2019HDU多校 Round4

08 K-th Closest Distance

题意:询问区间l,r中与数p的距离为第k大的数 求这个距离

题解:很裸的主席树 二分答案 然后可以用主席数判断在这个区间内 一段值域内出现的数

   之前没写过主席树求 统计小于区间某个数的个数 自作主张写的二分区间k小 loglog tle死

   看了汪聚聚的代码 才明白主席树功能的强大 以后会了

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;

int n, m, cnt, len;
int a[MAXN];
int b[MAXN];
int sum[MAXN << 5];
int ls[MAXN << 5];
int rs[MAXN << 5];
int t[MAXN];

int build(int l, int r) {
    int rt = ++cnt;
    int m = l + r >> 1;
    sum[rt] = 0;

    if(l < r) {
        ls[rt] = build(l, m);
        rs[rt] = build(m + 1, r);
    }
    return rt;
}

int add(int o, int l, int r, int k) {
    int rt = ++cnt;
    int m = l + r >> 1;
    ls[rt] = ls[o]; rs[rt] = rs[o]; sum[rt] = sum[o] + 1;

    if(l < r) {
        if(k <= m) ls[rt] = add(ls[o], l, m, k);
        else rs[rt] = add(rs[o], m + 1, r, k);
    }
    return rt;
}

int query(int x, int y, int l, int r, int ql, int qr) {
    if(ql <= l && qr >= r) return sum[y] - sum[x];

    int res = 0;
    int m = l + r >> 1;
    if(ql <= m) res += query(ls[x], ls[y], l, m, ql, qr);
    if(qr > m) res += query(rs[x], rs[y], m + 1, r, ql, qr);
    return res;
}

bool check(int ql, int qr, int x, int y, int k) {
    int t1 = lower_bound(b + 1, b + 1 + len, ql) - b;
    int t2 = lower_bound(b + 1, b + 1 + len, qr + 1) - b - 1;

    if(t1 > t2 || t2 > len || t1 > len) return 0;
    int tmp = query(t[x - 1], t[y], 1, len, t1, t2);
    if(tmp >= k) return 1;
    else return 0;
}

int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        cnt = 0;
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]), b[i] = a[i];
        sort(b + 1, b + 1 + n);
        len = unique(b + 1, b + 1 + n) - b - 1;

        t[0] = build(1, len);
        for(int i = 1; i <= n; i++) {
            int tt = lower_bound(b + 1, b + 1 + len, a[i]) - b;
            t[i] = add(t[i - 1], 1, len, tt);
        }

        int x = 0;
        for(int i = 1; i <= m; i++) {
            int l, r, p, k;
            scanf("%d%d%d%d", &l, &r, &p, &k);
            l ^= x, r ^= x, p ^= x, k ^= x;

            int l1 = 0, r1 = 1e6;
            int mid = l1 + r1 >> 1;
            while(l1 + 1 < r1) {
                mid = l1 + r1 >> 1;
                if(check(p - mid, p + mid, l, r, k)) r1 = mid;
                else l1 = mid;
            }
            if(check(p - l1, p + l1, l, r, k)) x = l1;
            else x = r1;
            printf("%d\n", x);
        }
    }
    return 0;
}
K-th Closest Distance

猜你喜欢

转载自www.cnblogs.com/lwqq3/p/11279827.html