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

链接: http://acm.hdu.edu.cn/showproblem.php?pid=6621
题意: 给一个数组,每次给 l ,r, p, k,问区间 [l, r] 的数与 p 作差的绝对值的第 k 小,这个绝对值是多少
思路: 二分答案ans,然后从主席树中查询[p - ans, p + ans]的区间和是否大于等于k即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5;
const int M=1e6;
int rt[N],ls[N*32],rs[N*32],sum[N*32];
int cnt;
void update(int &now,int pre,int l,int r,int k)
{
	now=++cnt;
	sum[now]=sum[pre]+1;
	ls[now]=ls[pre];
	rs[now]=rs[pre];
	if(l==r)
		return ;
	int mid=(l+r)>>1;
	if(k<=mid)
		update(ls[now],ls[pre],l,mid,k);
	else
		update(rs[now],rs[pre],mid+1,r,k);
}

int query(int now,int pre,int l,int r,int ql,int qr)
{
	if(l>=ql&&r<=qr)
	{
		return sum[now]-sum[pre];
	}
	int res=0;
	int mid=(l+r)>>1;
	if(ql<=mid)
		res+=query(ls[now],ls[pre],l,mid,ql,qr);
	if(qr>mid)
		res+=query(rs[now],rs[pre],mid+1,r,ql,qr);
	return res;
}

int solve(int x,int len,int l,int r)
{
	int L=max(1,x-len);
	int R=min(M,x+len);
	return query(rt[r],rt[l-1],1,M,L,R);
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		cnt=0;
		int n,m,ans=0;
		int l,r,p,k,x;
		scanf("%d%d",&n,&m);
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&x);
			update(rt[i],rt[i-1],1,M,x);
		}
		while(m--)
		{
			scanf("%d%d%d%d",&l,&r,&p,&k);
			l^=ans,r^=ans,p^=ans,k^=ans;
			int L=0,R=1e6;
			while(L<=R)
			{
				int mid=(L+R)>>1;
				if(solve(p,mid,l,r)<k)
					L=mid+1;
				else
					R=mid-1;
			}
			printf("%d\n",ans=L);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值