思路:
每次查询第k小,只有p在改变,所以我们可以枚举p的左右范围,因为题目中保证每个值都不同,
所以省略离散化,直接建立主席树,二分寻找p的左右范围,就是最终的答案。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6+10;
int a[maxn],n,m,cnt,root[maxn];
struct Node
{
int l,r,sum;
}Tree[maxn*40];
vector <int> vc;
int getid(int x)
{
return lower_bound(vc.begin(),vc.end(),x)-vc.begin()+1;
}
void build(int &rt,int l,int r)
{
rt = ++cnt;
Tree[rt].sum = 0;
if(l==r) return ;
int mid = (l+r)>>1;
build(Tree[rt].l,l,mid);
build(Tree[rt].r,mid+1,r);
}
void update(int num,int &rt,int lt,int l,int r)
{
rt = ++cnt;
Tree[rt] = Tree[lt];
Tree[rt].sum++;
if(l==r) return ;
int mid = (l+r)>>1;
if(num<=mid) update(num,Tree[rt].l,Tree[lt].l,l,mid);
else update(num,Tree[rt].r,Tree[lt].r,mid+1,r);
}
int query(int i,int j,int k1,int k2,int l,int r)
{
if(k1<=l&&r<=k2)
{
return Tree[j].sum-Tree[i].sum;
}
int mid = (l+r)>>1,ans = 0;
if(k1<=mid) ans += query(Tree[i].l,Tree[j].l,k1,k2,l,mid);
if(k2>mid) ans += query(Tree[i].r,Tree[j].r,k1,k2,mid+1,r);
return ans;
}
int main(void)
{
int T;
scanf("%d",&T);
while(T--)
{
cnt = 0;
scanf("%d%d",&n,&m);
build(root[0],1,maxn);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
update(a[i],root[i],root[i-1],1,maxn);
}
int ans = 0;
while(m--)
{
int l,r,p,k;
scanf("%d%d%d%d",&l,&r,&p,&k);
l ^= ans;r ^= ans;
p ^= ans;k ^= ans;
int L = 0,R = maxn;
while(L<=R)
{
int mid = (L+R)>>1;
if(query(root[l-1],root[r],max(1,p-mid),min(p+mid,maxn),1,maxn)>=k){
R = mid-1;
ans = mid;
}
else{
L = mid+1;
}
}
printf("%d\n",ans);
}
}
return 0;
}