Problem Description
传送门
思路:
对distance进行二分,在区间[p-dis,d+dis]中恰有k个时,dis就是答案;
查询一个区间有多少个数在[p-dis,d+dis]内可以使用主席树或者线段树,查询一次主席树的时间复杂度为O(logn),线段树的时间复杂度为O(logn*logn);
主席树做法:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<string>
#include<cstring>
#include<time.h>
#include<stdlib.h>
using namespace std;
typedef long long ll;
typedef pair<int, int>P;
const int INF = 0x3f3f3f3f;
const int NINF = 0xc0c0c0c0;
const int MAX_N = 100000+5;
const int S=(1<<18)+MAX_N*20;
struct node{
int a,id;
};
int n,m;
node data[MAX_N+1];
int ii[MAX_N+1];
int res;
int tot;
int tree[MAX_N+1];
int kat[S],lc[S],rc[S];
bool cmp(node A,node B){
return A.a<B.a;
}
int init(int l=1,int r=n){
int k=++tot;
kat[k]=0;
lc[k]=rc[k]=0;
if(l!=r){
lc[k]=init(l,(l+r)/2);
rc[k]=init((l+r)/2+1,r);
}
return k;
}
void build(int k,int p){
tree[k]=++tot;
int last=tree[k-1];
int l=1,r=n;
kat[tot]=kat[last]+1;
while(l<r){
if(p<=(l+r)/2){
lc[tot]=tot+1;
rc[tot]=rc[last];
kat[++tot]=kat[lc[last]]+1;
last=lc[last];
r=(l+r)/2;
}
else{
lc[tot]=lc[last];
rc[tot]=tot+1;
kat[++tot]=kat[rc[last]]+1;
last=rc[last];
l=(l+r)/2+1;
}
}
lc[tot]=rc[tot]=0;
}
int get(int x,int y,int p,int l=1,int r=n){
if(l==r)return kat[y]-kat[x];
if(p>(l+r)/2)return kat[lc[y]]-kat[lc[x]]+get(rc[x],rc[y],p,(l+r)/2+1,r);
return get(lc[x],lc[y],p,l,(l+r)/2);
}
int get2(int l,int r,int x){
int lb=0,ub=n+1;
while(ub-lb>1){
int mid=(lb+ub)/2;
if(data[mid].a<=x)lb=mid;
else ub=mid;
}
if(lb==0)return 0;
return get(tree[l-1],tree[r],lb);
}
int get3(int l,int r,int x,int y){
return get2(l,r,y)-get2(l,r,x-1);
}
void solve(int l,int r,int p,int k){
int lb=-1,ub=1e8;
while(ub-lb>1){
int mid=(lb+ub)/2;
if(get3(l,r,p-mid,p+mid)>=k)ub=mid;
else lb=mid;
}
res=ub;
printf("%d\n",res);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&data[i].a);
data[i].id=i;
}
sort(data+1,data+n+1,cmp);
for(int i=1;i<=n;i++)ii[data[i].id]=i;
res=0;
tot=0;
tree[0]=init();
for(int i=1;i<=n;i++)build(i,ii[i]);
int l,r,p,k;
while(m--){
scanf("%d%d%d%d",&l,&r,&p,&k);
l^=res,r^=res,p^=res,k^=res;
solve(l,r,p,k);
}
}
return 0;
}
线段树做法:
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<string>
#include<cstring>
#include<time.h>
#include<stdlib.h>
using namespace std;
typedef long long ll;
typedef pair<int, int>P;
const int INF = 0x3f3f3f3f;
const int NINF = 0xc0c0c0c0;
const int MAX_N = 100000+5;
const int S=(1<<18);
int n,m;
int a[MAX_N];
int res;
vector<int> dat[S];
void init(int k=0,int l=0,int r=n){
if(r-l==1){
dat[k].resize(1);
dat[k][0]=a[l];
return;
}
int lc=k*2+1,rc=k*2+2;
init(lc,l,(l+r)/2);
init(rc,(l+r)/2,r);
dat[k].resize(r-l);
merge(dat[lc].begin(),dat[lc].end(),dat[rc].begin(),dat[rc].end(),dat[k].begin());
}
int query(int x,int y,int z,int k=0,int l=0,int r=n){
if(x<=l&&y>=r){
return upper_bound(dat[k].begin(),dat[k].end(),z)-dat[k].begin();
}
if(y<=l||x>=r)return 0;
return query(x,y,z,k*2+1,l,(l+r)/2)+query(x,y,z,k*2+2,(l+r)/2,r);
}
int get(int x,int y,int l,int r){
return query(l,r,y)-query(l,r,x-1);
}
void solve(int l,int r,int p,int k){
int lb=-1,ub=1e8;
while(ub-lb>1){
int mid=(lb+ub)/2;
if(get(p-mid,p+mid,l,r)>=k)ub=mid;
else lb=mid;
}
res=ub;
printf("%d\n",res);
}
int main(){
int T;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)scanf("%d",a+i);
res=0;
init();
int l,r,p,k;
while(m--){
scanf("%d%d%d%d",&l,&r,&p,&k);
l^=res,r^=res,p^=res,k^=res;
solve(l-1,r,p,k);
}
}
return 0;
}