HDU - 6621 K-th Closest Distance(主席树+二分)

You have an array: a1, a2, , an and you must answer for some queries. 
For each query, you are given an interval [L, R] and two numbers p and K. Your goal is to find the Kth closest distance between p and aL, aL+1, ..., aR. 
The distance between p and ai is equal to |p - ai|. 
For example: 
A = {31, 2, 5, 45, 4 } and L = 2, R = 5, p = 3, K = 2. 
|p - a2| = 1, |p - a3| = 2, |p - a4| = 42, |p - a5| = 1. 
Sorted distance is {1, 1, 2, 42}. Thus, the 2nd closest distance is 1.

Input

The first line of the input contains an integer T (1 <= T <= 3) denoting the number of test cases. 
For each test case: 
冘The first line contains two integers n and m (1 <= n, m <= 10^5) denoting the size of array and number of queries. 
The second line contains n space-separated integers a1, a2, ..., an (1 <= ai <= 10^6). Each value of array is unique. 
Each of the next m lines contains four integers L', R', p' and K'. 
From these 4 numbers, you must get a real query L, R, p, K like this: 
L = L' xor X, R = R' xor X, p = p' xor X, K = K' xor X, where X is just previous answer and at the beginning, X = 0. 
(1 <= L < R <= n, 1 <= p <= 10^6, 1 <= K <= 169, R - L + 1 >= K).

Output

For each query print a single line containing the Kth closest distance between p and aL, aL+1, ..., aR.

Sample Input

1
5 2
31 2 5 45 4
1 5 5 1
2 5 3 2

Sample Output

0
1

                    建立好主席树,然后每次查询对距离二分就好了~PS(注意这个傻逼题要求每次l,r,p,k都要对上一次答案进行异或,wa了一年因为这个有点的没得,真的烦)。

#include
using namespace std;
const int maxn = 100005;
const int M = maxn * 30;
int n, q, tot, m;
int a[maxn], t[maxn];
int T[maxn], lson[M], rson[M], c[M];
void Init_hash() {
	for (int i = 1; i <= n; i++)
		t[i] = a[i];
	sort(t + 1, t + 1 + n);
	m = unique(t + 1, t + 1 + n) - t - 1;
}
int build(int l, int r) {
	int root = tot++;
	c[root] = 0;
	if (l != r) {
		int mid = (l + r) >> 1;
		lson[root] = build(l, mid);
		rson[root] = build(mid + 1, r);
	}
	return root;
}
int update(int root, int pos, int val) {
	int newroot = tot++, tmp = newroot;
	c[newroot] = c[root] + val;
	int l = 1, r = m;
	while (l < r) {
		int mid = (l + r) >> 1;
		if (pos <= mid) {
			lson[newroot] = tot++; rson[newroot] = rson[root];
			newroot = lson[newroot]; root = lson[root];
			r = mid;
		}
		else {
			rson[newroot] = tot++; lson[newroot] = lson[root];
			newroot = rson[newroot]; root = rson[root];
			l = mid + 1;
		}
		c[newroot] = c[root] + val;
	}
	return tmp;
}
int Hash(int x) {
	return lower_bound(t + 1, t + 1 + m, x) - t;
}
int query(int left_root, int right_root, int l, int r, int L, int R) {
	if (L <= t[l] && t[r] <= R) {
		return  c[right_root] - c[left_root];
	}
	int mid = (l + r) >> 1, sum = 0;
	if (L <= t[mid]) {
		sum += query(lson[left_root], lson[right_root], l, mid, L, R);
	}
	if (R >= t[mid + 1]) {
		sum += query(rson[left_root], rson[right_root], mid + 1, r, L, R);
	}
	return sum;
}
int main() {
	int te; scanf("%d", &te);
	while (te--) {
		scanf("%d%d", &n, &q);
		tot = 0;
		for (int i = 1; i <= n; i++)
			scanf("%d", &a[i]);
		Init_hash();
		T[0] = build(1, m);
		for (int i = 1; i <= n; i++) {
			int pos = Hash(a[i]);
			T[i] = update(T[i - 1], pos, 1);
		}

		int re = 0;
		while (q--) {
			int l, r, k, p;
			scanf("%d%d%d%d", &l, &r, &p, &k);
			l ^= re; r ^= re; p ^= re; k ^= re;
			int li = 0, ri = 1000005, ans = -1;
			while (li <= ri) {
				int mid = (li + ri) >> 1;
				int limit = p - mid, rimit = p + mid;
				int res = query(T[l - 1], T[r], 1, m, limit, rimit);
				if (res >= k) {
					ans = mid;
					ri = mid - 1;
				}
				else li = mid + 1;
			}
			printf("%d\n", ans);
			re = ans;
		}
	}
	return 0;
}

 

你可能感兴趣的:(数据结构)