Question: Give you a sequence of n numbers, m times of inquiry, each time you find a point in the interval [l, r] which is nearest to the point p to the k, and output the K distance.
Thoughts: We use the chairman tree to count the number of occurrences of each number in the interval, and then dichotomize the answer to check whether the number of [p - mid, p + mid] is greater than or equal to k in the interval. In some cases, it will prove that the current answer is feasible, and the idea is still very clever.
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 1e5 + 10; int sum[maxn << 5], root[maxn], ls[maxn << 5], rs[maxn << 5]; int a[maxn], b[maxn]; int n, m, tot, len; int update(int k, int l, int r, int rt) { int now = ++tot; ls[now] = ls[rt], rs[now] = rs[rt], sum[now] = sum[rt] + 1; if(l == r) return now; int mid = (l + r) >> 1; if(k <= mid) ls[now] = update(k, l, mid, ls[now]); else rs[now] = update(k, mid + 1, r, rs[now]); return now; } int query(int u, int v, int l, int r,int ql,int qr) //Number of query intervals { if(ql <= l && r <= qr) return sum[v] - sum[u]; int mid = (l + r) >> 1; int res = 0; if(ql <= mid) res += query(ls[u], ls[v], l, mid, ql, qr); if(qr > mid) res += query(rs[u], rs[v], mid + 1, r, ql, qr); return res; } void init() { tot = 0, len = 1e6; scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) { scanf("%d", &a[i]); } root[0] = 0; for(int i = 1; i <= n; ++i) root[i] = update(a[i], 1, len, root[i - 1]); } int main() { int t; scanf("%d", &t); while(t--) { init(); int l, r, p, k, x = 0; while(m--) { scanf("%d%d%d%d", &l, &r, &p, &k); l ^= x, r ^= x, p ^= x, k ^= x; int L = 0, R = len; while(L <= R) //Two points difference { int mid = (L + R) >> 1; if(query(root[l - 1], root[r], 1, len, max(1, p - mid), min(len, p + mid)) >= k) R = mid - 1, x = mid; else L = mid + 1; } printf("%d\n", x); } } return 0; }