題意:給定長度爲\(n\)的數列,現有m次查詢,每組詢問給\(l,r,p,k\),問對\(l<=i<=r\),\(|p-a[i]|\)的第k小值。數據強制在線。php
題解:二分答案ans,用主席樹查詢\(a[l]\)到\(a[r]\)之間\([p-ans,p+ans]\)的個數,個數爲k即爲答案。node
因爲強制在線,因此建主席樹不能離散化。能夠動態空間直接建樹。c++
#include<bits/stdc++.h> using namespace std; const int maxn=100005; int n,m; const int N=1e6; struct node{ int ls,rs,sum; }; node tree[maxn*22]; int rt[maxn],tot=0; int update(int l,int r,int x,int pre){ int now=++tot; tree[now]=tree[pre]; if(l==r){ tree[now].sum++; return now; } int mid=(l+r)>>1; if(x>mid) tree[now].rs=update(mid+1,r,x,tree[pre].rs); else tree[now].ls=update(l,mid,x,tree[pre].ls); tree[now].sum++; return now; } int ask(int l,int r,int il,int ir,int root1,int root2){ if(r<il||l>ir) return 0; if(l>=il&&r<=ir) return tree[root2].sum-tree[root1].sum; int mid=(l+r)>>1; return ask(l,mid,il,ir,tree[root1].ls,tree[root2].ls)+ask(mid+1,r,il,ir,tree[root1].rs,tree[root2].rs); } int jud(int len,int p,int rt1,int rt2){ int l=max(1,p-len),r=min(N,p+len); return ask(1,N,l,r,rt1,rt2); } int solve(int l,int r,int p,int k){ int rt1=rt[l-1],rt2=rt[r]; int ll=0,rr=N; while(ll<rr){ int mid=(ll+rr)>>1; if(jud(mid,p,rt1,rt2)>=k) rr=mid; else ll=mid+1; } return ll; } int main(){ int T; cin >> T; while(T--){ tot=0; tree[0].sum=tree[0].ls=tree[0].rs=0; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { int x; scanf("%d",&x); rt[i]=update(1,N,x,rt[i-1]); } int las=0; while(m--){ int l,r,p,k; scanf("%d%d%d%d",&l,&r,&p,&k); l^=las; r^=las; p^=las; k^=las; printf("%d\n",las=solve(l,r,p,k)); } } return 0; }