题意:n个数,q次查询,查询[l , r] 内, | a[i] - p | 第k大的数。
思路:主席树维护权值,要求|a[i]-p|的第k大,可以二分答案,若区间[l,r]内的数在范围[p-ans,p+ans]的数等于k,则ans就是答案,所以二分答案求出来,复杂度O(q*log(m)*log(m))。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 10;
int n, M, a[N], cnt, root[N], t;
struct node {
int l, r, sum;
} zxs[N * 40];
void add(int l, int r, int pre, int &now, int pos) {
zxs[++cnt] = zxs[pre], now = cnt, zxs[cnt].sum++;
if(l == r)
return;
int m = (l + r) >> 1;
if(pos <= m)
add(l, m, zxs[pre].l, zxs[now].l, pos);
else
add(m + 1, r, zxs[pre].r, zxs[now].r, pos);
}
int query(int pl, int pr, int l, int r, int L, int R) {
if(pl <= l && r <= pr)
return zxs[R].sum - zxs[L].sum;
int m = (l + r) >> 1, ans = 0;
if(pl <= m)
ans += query(pl, pr, l, m, zxs[L].l, zxs[R].l);
if(pr > m)
ans += query(pl, pr, m + 1, r, zxs[L].r, zxs[R].r);
return ans;
}
int main() {
freopen("14162.in","r",stdin);
freopen("14162.out","w",stdout);
scanf("%d", &t);
while(t--) {
cnt = 0;
memset(root, 0, sizeof root);
scanf("%d %d", &n, &M);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]), add(1, N, root[i - 1], root[i], a[i]);
int x = 0;
while(M--) {
int l, r, p, k, pl = 0, pr = N;
scanf("%d %d %d %d", &l, &r, &p, &k);
l = (l ^ x), r = (r ^ x), p = (p ^ x), k = (k ^ x);
while(pl <= pr) {
int m = (pl + pr) >> 1;
if(query(max(1, p - m), min(N, p + m), 1, N, root[l - 1], root[r]) >= k) {
x = m;
pr = m - 1;
} else
pl = m + 1;
}
printf("%d\n", x);
}
}
return 0;
}