主席树+二分
二分与p的距离,确定与[p-mid,p+mid]这个区间中有多少个点,如果大于等于k个,说明这个区间合理,可以缩小寻找范围,否则增大寻找范围。
#include
using namespace std;
const int maxn=1e5+10;
int root[maxn*40];
int sum[maxn*40];
int ls[maxn*40];
int rs[maxn*40];
int a[maxn];
int tot,n,m;
void update(int &rt,int l,int r,int last,int p)
{
rt=++tot;
ls[rt]=ls[last];
rs[rt]=rs[last];
sum[rt]=sum[last]+1;
if(l==r)
return ;
int mid=l+r>>1;
if(p<=mid)
update(ls[rt],l,mid,ls[last],p);
else
update(rs[rt],mid+1,r,rs[last],p);
}
int query(int l,int r,int x,int y,int k1,int k2)
{
if(k1<=l&&r<=k2)
return sum[y]-sum[x];
int mid=l+r>>1;
int ans=0;
if(k1<=mid)
ans+=query(l,mid,ls[x],ls[y],k1,k2);
if(k2>mid)
{
ans+=query(mid+1,r,rs[x],rs[y],k1,k2);
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
tot=0;
memset(root,0,sizeof(root));
memset(ls,0,sizeof(ls));
memset(rs,0,sizeof(rs));
memset(sum,0,sizeof(sum));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
update(root[i],1,1000000,root[i-1],a[i]);
}
int ans=0;
int x,y,p,k;
while(m--)
{
scanf("%d%d%d%d",&x,&y,&p,&k);
x^=ans;y^=ans;p^=ans;k^=ans;
int l=0,r=1000000;
while(l<=r)
{
int mid=l+r>>1;
if(query(1,1000000,root[x-1],root[y],max(1,p-mid),min(1000000,p+mid))>=k)
{
r=mid-1;
ans=mid;
}
else
l=mid+1;
}
printf("%d\n",ans);
}
}
return 0;
}