题目
题意:n个数,m个询问[l,r,p,k] 区间[l,r]最接近p的第k个数。强制在线。
思路:每次二分答案mid,查找区间[l,r]里面[p-mid,p+mid]的数>=k right=mid;主席树维护.
#include<cstdio>
#include<algorithm>
using namespace std;
struct tree{int l,r,sum;}t[20000000];
int root[100001],a[100001],sz;
inline void update(int l,int r,int &x,int y,int n)
{
t[x=(++sz)]=t[y],++t[sz].sum;
if(l==r) return;
int mid=(l+r)>>1;
if(n<=mid) update(l,mid,t[x].l,t[y].l,n);
else update(mid+1,r,t[x].r,t[y].r,n);
}
inline int query(int cl,int cr,int l,int r,int x,int y){
if(cl<=l&&r<=cr) return t[y].sum-t[x].sum;
int mid=(l+r)>>1,ans=0;
if(cl<=mid) ans+=query(cl,cr,l,mid,t[x].l,t[y].l);
if(cr>mid) ans+=query(cl,cr,mid+1,r,t[x].r,t[y].r);
return ans;
}
int main(){
int T,n,m,X,Max,l,r,p,k,low,high,mid;scanf("%d",&T);
while(T--){
sz=X=Max=0;scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i) scanf("%d",&a[i]),Max=max(Max,a[i]);
for(int i=1;i<=n;++i) update(1,Max,root[i],root[i-1],a[i]);
while(m--){
scanf("%d%d%d%d",&l,&r,&p,&k);l^=X,r^=X,p^=X,k^=X;
low=0,high=max(p-1,Max-p);
while(low<high){
mid=(low+high)>>1;
if(query(max(p-mid,1),min(p+mid,Max),1,Max,root[l-1],root[r])>=k) high=mid;
else low=mid+1;
}
printf("%d\n",X=high);
}
}
}