K-th Closest Distance (主席树)

题目链接: K-th Closest Distance

大致题意

给定一个长度为n序列, 有m次询问. 每次询问给出l, r, p 和 k. 表示询问序列[l, r]区间中和p的绝对值之差第k小的数字.

解题思路

主席树, 这不还是求一个区间第k小的问题, 所以首先我们应该想到用主席树来维护.

考虑到询问, 每次要求与p绝对值之差第k小, 因此我们不妨二分, 对于当前mid, 我们统计有多少个数的值位于[p - mid, p + mid]区间.

AC代码

#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
typedef long long ll;
const int N = 1E6 + 10;
int w[N];
struct node {
	int l, r;
	int cou;
}t[N << 5]; int root[N], ind;
int build(int a, int c, int tl, int tr, int p) {
	int x = ++ind; 
	t[x] = t[p]; t[x].cou += c; 
	if (tl == tr) return x;

	int mid = tl + tr >> 1;
	if (a <= mid) t[x].l = build(a, c, tl, mid, t[p].l);
	else t[x].r = build(a, c, mid + 1, tr, t[p].r);
	return x;
}

int ask(int l, int r, int tl, int tr, int p, int x) {
	if (l <= tl && r >= tr) return t[x].cou - t[p].cou;
	int mid = tl + tr >> 1;
	int res = 0;
	if (l <= mid) res += ask(l, r, tl, mid, t[p].l, t[x].l);
	if (r > mid) res += ask(l, r, mid + 1, tr, t[p].r, t[x].r);
	return res;
}
int main()
{
	int T; cin >> T;
	while (T--) {
		ind = 0;
		int n, m; cin >> n >> m;
		int len = N - 5; 
		rep(i, n) {
			scanf("%d", &w[i]);
			root[i] = build(w[i], 1, 1, len, root[i - 1]);
		}
        
		int last = 0;
		rep(i, m) {
			int l, r, p, k; scanf("%d %d %d %d", &l, &r, &p, &k);
			l ^= last, r ^= last, p ^= last, k ^= last;
			int L = 0, R = len;
			while (L < R) {
				int mid = L + R >> 1;
				int cou = ask(max(1, p - mid), min(len, p + mid), 1, len, root[l - 1], root[r]); //优化左右边界

				if (cou >= k) R = mid;
				else L = mid + 1;
			}
			printf("%d\n", last = L);
		}
	}
	return 0;
}

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

逍遥Fau

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值