题目链接:HDU - 6621
题意:给定n个数字,q次询问,每次给出l,r,p,k。询问区间l,r内所有数字与p的差值的绝对值中排名第k大的是多少。
看到题目给了15秒的时限,再看看题目数据很容易想到单次查询应该是log*log的复杂度,再观察这个答案发现具有单调性,于是想到要二分答案,答案确定后,就可以知道查询区间了,我们只需要查询区间[p-mid,p+mid]内有多少数字即可。
关于单调性:二分的答案越小,查询的区间就越小,产生的值固然也越小。
询问是在线的。
#include
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
struct Tree{
int lc,rc;
int sum;
}tree[maxn*50];
int root[maxn],tot;
int build(int l,int r){
int k=++tot;
tree[k].sum=0;
if(l==r) return k;
int mid=(l+r)>>1;
tree[k].lc=build(l,mid);
tree[k].rc=build(mid+1,r);
return k;
}
int updata(int p,int l,int r,int id,int val){
int k=++tot;
tree[k]=tree[p];
if(l==r){
tree[k].sum+=val;
return k;
}
int mid=(l+r)>>1;
if(id<=mid) tree[k].lc=updata(tree[p].lc,l,mid,id,val);
else tree[k].rc=updata(tree[p].rc,mid+1,r,id,val);
tree[k].sum=tree[tree[k].lc].sum+tree[tree[k].rc].sum;
return k;
}
int myfind(int p,int q,int l,int r,int L,int R){
if(L>R) return 0;
if(l>=L&&r<=R) return tree[p].sum-tree[q].sum;
int mid=(l+r)>>1;
int res=0;
if(L<=mid) res+=myfind(tree[p].lc,tree[q].lc,l,mid,L,R);
if(R>mid) res+=myfind(tree[p].rc,tree[q].rc,mid+1,r,L,R);
return res;
}
int a[maxn],b[maxn],m;
void quchong(int n){
sort(b+1,b+1+n);
m=unique(b+1,b+1+n)-b-1;
}
int getid(int x){
return lower_bound(b+1,b+1+m,x)-b;
}
int erfen(int l,int r,int x){//第一个大于等于;
int mid;
while(l<=r){
mid=(l+r)>>1;
if(b[mid]>1;
if(b[mid]<=x) l=mid+1;
else r=mid-1;
}
return r;
}
int main(){
int t;
scanf("%d",&t);
int n,q,id;
int l,r,p,k,hh,ll,rr;
while(t--){
scanf("%d%d",&n,&q);
for(int i=1;i<=n;++i){
scanf("%d",&a[i]);
b[i]=a[i];
}
quchong(n);
root[0]=build(1,m);
for(int i=1;i<=n;++i)
root[i]=updata(root[i-1],1,m,getid(a[i]),1);
int x=0;
while(q--){
scanf("%d%d%d%d",&l,&r,&p,&k);
l=l^x,r=r^x,p=p^x,k=k^x;
int L=0,R=1000000,mid;
while(L<=R){
mid=(L+R)>>1;
ll=erfen(1,m,p-mid);
rr=erfen2(1,m,p+mid);
if(ll>m) --ll;
if(rr<=0) ++rr;
hh=myfind(root[r],root[l-1],1,m,ll,rr);
if(hh>=k) R=mid-1;
else L=mid+1;
}
x=L;
printf("%d\n",x);
}
}
return 0;
}