链接: 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;
}