K-th Closest Distance
Sample Input
1
5 2
31 2 5 45 4
1 5 5 1
2 5 3 2
Sample Output
0
1
样例
第一行 T 组数据
第二行 两个整数 n,m;表示n 个数,m 次查询
第三行 n 个整数(1 <= a[i] <= 1e6)
写下来 m 行,每行4个数,l,r,p,k;
题意
给出一个数组,每次查询把 [ l,r ] 区间的每个数和 p 相减得到的绝对值,找到第 k 小的绝对值,将其输出,另外除了第一次查询,剩下的每次查询的 l,r,p,k 需要与上一次查询的答案进行异或才是真正的 l,r,q,k
思路
题目就是要求区间内距离 p 第 k 近的数,这个数与 p 的距离是多少,我们可以二分距离答案ans,然后判断在[ l , r ] 这个区间里的数在值域 [ p - ans, p + ans ] 里的数有没有 k 个,如果>= k 个,我们就缩小值域范围,即缩小ans,否则就扩大ans;
题解是说线段树加二分,我是用主席树加二分;
因为每个数的范围就 [1,1e6],所以不用离散化,直接把给的数组,建立一颗主席树;然后对答案距离ans进行二分,二分到最后结果就是正确答案
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#define maxn 100100
using namespace std;
struct node{
int l, r, sum;
}tree[maxn*40];
int a[maxn], cnt, root[maxn];
void insert(int l, int r, int pre, int &now, int p){
tree[++cnt] = tree[pre];
now = cnt;
tree[now].sum++;
if(l == r) return;
int mid = (l+r)>>1;
if(p <= mid) insert(l, mid, tree[pre].l, tree[now].l, p);
else insert(mid+1, r, tree[pre].r, tree[now].r, p);
}
int query(int l, int r, int L, int R, int ql, int qr){
if(ql == l && qr == r){
return tree[R].sum - tree[L].sum;
}
int mid = (l + r)>>1;
if(qr <= mid){
return query(l, mid, tree[L].l, tree[R].l, ql, qr);
}
else if(ql > mid){
return query(mid+1, r, tree[L].r, tree[R].r, ql, qr);
}
else{
int ans = query(l, mid, tree[L].l, tree[R].l, ql, mid);
ans += query(mid+1, r, tree[L].r, tree[R].r, mid+1, qr);
return ans;
}
}
void init(){
cnt = 0;
tree[cnt].l = 0;
tree[cnt].r = 0;
tree[cnt].sum = 0;
root[cnt] = 0;
}
int main(){
int t;
scanf("%d", &t);
while(t--){
int n, m, L, R, p, k, l = 1001000, r = -1;
cnt = 0;
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++){
scanf("%d", &a[i]);
l = min(l, a[i]);
r = max(r, a[i]);
}
for(int i = 1; i <= n; i++) insert(l, r, root[i - 1], root[i], a[i]);
int ans = 0;
while(m--){
scanf("%d%d%d%d", &L, &R, &p, &k);
int low = 0, up = 1e6, mid;
L ^= ans;
R ^= ans;
p ^= ans;
k ^= ans;
while(low <= up){//二分答案
mid = (low + up)>>1;
if(query(l, r, root[L-1], root[R], max(l, p - mid), min(r, p + mid)) >= k){
ans = mid;
up = mid - 1;
}
else low = mid+1;
}
printf("%d\n", ans);
}
}
}