题目链接:Click here
大致题意:q次询问,每次询问你区间[L,R]中|p-ai|的值第k小的是多少
Solution:
直接找是很困难的,我们考虑二分答案,那么本题就十分简单了
我们对权值维护一颗主席树,每次只要查询区间[L,R]中权值在[p-mid,p+mid]之的数的个数就行了
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
int n,m,maxn,lst,L,R,k,p,a[N];
int rt[N],sz[N*40];
int tot,ls[N*40],rs[N*40];
int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;
}
void build(int &q,int l,int r){
q=++tot;sz[q]=0;
if(l==r) return ;
int mid=l+r>>1;
build(ls[q],l,mid);
build(rs[q],mid+1,r);
}
void ins(int &q,int lst,int l,int r,int x){
q=++tot;sz[q]=sz[lst]+1;
ls[q]=ls[lst],rs[q]=rs[lst];
if(l==r) return ;
int mid=l+r>>1;
if(mid>=x) ins(ls[q],ls[lst],l,mid,x);
else ins(rs[q],rs[lst],mid+1,r,x);
}
int query(int q,int lst,int l,int r,int x,int y){
if(l>=x&&r<=y) return sz[q]-sz[lst];
int mid=l+r>>1,re=0;
if(mid>=x) re+=query(ls[q],ls[lst],l,mid,x,y);
if(mid<y) re+=query(rs[q],rs[lst],mid+1,r,x,y);
return re;
}
int check(int x){
int l=max(0,p-x),r=min(maxn,p+x);
int v=query(rt[R],rt[L-1],1,maxn,l,r);
return v>=k;
}
void solve(){
maxn=lst=tot=0;
n=read(),m=read();
for(int i=1;i<=n;i++){
a[i]=read();
maxn=max(maxn,a[i]);
}build(rt[0],1,maxn);
for(int i=1;i<=n;i++)
ins(rt[i],rt[i-1],1,maxn,a[i]);
for(int i=1;i<=m;i++){
L=read(),R=read(),p=read(),k=read();
L^=lst,R^=lst,p^=lst,k^=lst;
int l=0,r=maxn,re=maxn;
while(l<=r){
int mid=l+r>>1;
if(check(mid)) re=mid,r=mid-1;
else l=mid+1;
}printf("%d
",re);lst=re;
}
}
int main(){
int t=read();
while(t--) solve();
return 0;
}