题目链接: K-th Closest Distance
大致题意
给定一个长度为n序列, 有m次询问. 每次询问给出l, r, p 和 k. 表示询问序列[l, r]区间中和p的绝对值之差第k小的数字.
解题思路
主席树, 这不还是求一个区间第k小的问题, 所以首先我们应该想到用主席树来维护.
考虑到询问, 每次要求与p绝对值之差第k小, 因此我们不妨二分, 对于当前mid, 我们统计有多少个数的值位于[p - mid, p + mid]区间.
AC代码
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E6 + 10;
int w[N];
struct node {
int l, r;
int cou;
}t[N << 5]; int root[N], ind;
int build(int a, int c, int tl, int tr, int p) {
int x = ++ind;
t[x] = t[p]; t[x].cou += c;
if (tl == tr) return x;
int mid = tl + tr >> 1;
if (a <= mid) t[x].l = build(a, c, tl, mid, t[p].l);
else t[x].r = build(a, c, mid + 1, tr, t[p].r);
return x;
}
int ask(int l, int r, int tl, int tr, int p, int x) {
if (l <= tl && r >= tr) return t[x].cou - t[p].cou;
int mid = tl + tr >> 1;
int res = 0;
if (l <= mid) res += ask(l, r, tl, mid, t[p].l, t[x].l);
if (r > mid) res += ask(l, r, mid + 1, tr, t[p].r, t[x].r);
return res;
}
int main()
{
int T; cin >> T;
while (T--) {
ind = 0;
int n, m; cin >> n >> m;
int len = N - 5;
rep(i, n) {
scanf("%d", &w[i]);
root[i] = build(w[i], 1, 1, len, root[i - 1]);
}
int last = 0;
rep(i, m) {
int l, r, p, k; scanf("%d %d %d %d", &l, &r, &p, &k);
l ^= last, r ^= last, p ^= last, k ^= last;
int L = 0, R = len;
while (L < R) {
int mid = L + R >> 1;
int cou = ask(max(1, p - mid), min(len, p + mid), 1, len, root[l - 1], root[r]); //优化左右边界
if (cou >= k) R = mid;
else L = mid + 1;
}
printf("%d\n", last = L);
}
}
return 0;
}