题意:n个数,q次查询,查询[l , r] 内, | a[i] - p | 第k大的数
思路:主席树维护下权值大小,二分答案,查询区间[p - mid, p + mid] 的个数
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<map> #include<vector> #include<queue> #include<cmath> using namespace std; const int N = 1e5 + 10; const int M = 1e6; struct node { int l, r; int val; }tree[N * 55]; int root[N], tot; int n, q, a[N]; int update(int pre, int pl, int pr, int val) { int cur = ++tot; tree[cur] = tree[pre]; tree[cur].val ++; if(pl == pr) return cur; int mid = (pl + pr) >> 1; if(val <= mid) tree[cur].l = update(tree[pre].l, pl, mid, val); else tree[cur].r = update(tree[pre].r, mid + 1, pr, val); return cur; } int k, cnt; int query(int pl, int pr, int l, int r, int rt, int lt) { if(pl <= l && r <= pr) { return tree[rt].val - tree[lt].val; } int mid = (l + r) >> 1; int res = 0; if(pl <= mid) res += query(pl, pr, l, mid, tree[rt].l, tree[lt].l); if(pr > mid) res += query(pl, pr, mid + 1, r, tree[rt].r, tree[lt].r); return res; } int main( ) { int T, prex; int l, r, p; int pl, pr, mid; scanf("%d", &T); while(T--) { scanf("%d %d", &n, &q); for(int i = 1; i <= n; i++) { scanf("%d", &a[i]); root[i] = update(root[i - 1], 1, M, a[i]); } prex = 0; while(q--) { scanf("%d %d %d %d", &l, &r, &p, &k); l = l ^ prex; r = r ^ prex; p = p ^ prex; k = k ^ prex; pl = 0, pr = M; while(pl <= pr) { mid = (pl + pr) >> 1; if(query(max(1, p - mid), min(M, p + mid), 1, M, root[r], root[l - 1]) >= k) { prex = mid; pr = mid - 1; } else pl = mid + 1; } printf("%d ", prex); } } return 0; }