题意:给一个数组,每次给 l ,r, p, k,问区间 [l, r] 的数与 p 作差的绝对值的第 k 小,这个绝对值是多少

分析:首先我们先分析单次查询怎么做:

题目给出的数据与多次查询已经在提示着我们在用数据结构去解决这个问题,对于常见的处理区间的数据结构首选线段树啦:

我觉得这道题的关键在于此:我们需要去二分答案ans,  为什么呢? 我们这样观察 ,对于 | p-a[i] | <= ans  等于 p-ans<=a[i] <=p+ans   那问题就转化为查询[L,R] 区间里面在[p-ans,p+ans] 范围的a[i] 有多少个  。这显然是到主席树的题目;

我们明白主席树的原理是多颗权值线段树 , 那我们就把a[i]当成下标,权值为出现的次数,那我们就是查询[L,R] 编号是权值线段树里面[p-ans,p+ans] 范围的a[i] 有多少个 。

主席树:

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+;
int tot;
int lson[N],rson[N],sum[N],tr[N];
void build(int &rt,int l,int r){
rt=++tot;
if(l==r) return ;
int mid=(l+r)>>;
build(lson[rt],l,mid);
build(rson[rt],mid+,r);
}
void updata(int root,int &rt,int p,int l,int r){
rt=++tot;
lson[rt]=lson[root],rson[rt]=rson[root];
sum[rt]=sum[root]+;
if(l==r) return ;
int mid=(l+r)>>;
if(p<=mid) updata(lson[root],lson[rt],p,l,mid);
else updata(rson[root],rson[rt],p,mid+,r);
}
int query(int rt_,int rt,int L,int R,int l,int r){
if(l<=L&&R<=r){
return sum[rt_]-sum[rt];
}
int mid=(L+R)>>;
int ans=;
if(l<=mid)
ans+=query(lson[rt_],lson[rt],L,mid,l,r);
if(mid<r)
ans+=query(rson[rt_],rson[rt],mid+,R,l,r);
return ans;
}
int main(){
int _;scanf("%d",&_);
while(_--){
int n,m;scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
{
int x;scanf("%d",&x);
updata(tr[i-],tr[i],x,,N);
}
int T=;
for(int i=;i<=m;i++){
int L,R,p,k; scanf("%d%d%d%d",&L,&R,&p,&k);
L^=T,R^=T,p^=T,k^=T;
int LL=,RR=1e6,ans=;
while(LL<=RR){
int mid=(LL+RR)>>;
int l=max(,p-mid);
int r=min(N,p+mid);
if(query(tr[R],tr[L-],,N,l,r)>=k){
RR=mid-;ans=mid;
}
else LL=mid+;
}
T=ans;
printf("%d\n",ans);
} }
return ;
}

权值线段树的做法:

要解决的问题依然没有变;

线段树的每个节点都存着对应区间有序的序列,比如{5,1,2,3,4} ,对于这样的一个序列,线段树的根节点表示的是区间[1,5] 节点里面存有序列{1,2,3,4,5} 那我们查询p-ans<=a[i] <=p+ans  ,就二分{1,2,3,4,5}这个有序的序列有多少个大于p+ans,多少个

大于p-ans-1,在相减;这钟线段树,真的是前所未闻........

#include<bits/stdc++.h>

using namespace std;
const int N=1e5+;
vector<int>v[N];
vector<int>::iterator it;
int a[N];
void build(int l,int r,int rt){
v[rt].clear();
for(int i=l;i<=r;i++)
v[rt].push_back(a[i]);
sort(v[rt].begin(),v[rt].end());
if(l==r) return ;
int mid=(l+r)>>;
build(l,mid,rt<<);
build(mid+,r,rt<<|);
}
int query(int L,int R,int rt,int l,int r,int val){
if(l<=L&&R<=r){
it=upper_bound(v[rt].begin(),v[rt].end(),val);
return it-v[rt].begin();
}
int ans=;
int mid=(L+R)>>;
if(l<=mid)
ans+=query(L,mid,rt<<,l,r,val);
if(mid<r)
ans+=query(mid+,R,rt<<|,l,r,val);
return ans;
}
int main(){
int _; scanf("%d",&_);
while(_--){
int n,m; scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) scanf("%d",&a[i]);
build(,n,);
int L1=,R1=,p1=,k1=;
int T=;
for(int i=;i<=m;i++){
int L,R,p,k;
scanf("%d%d%d%d",&L,&R,&p,&k);
L^=T,R^=T,p^=T,k^=T;
int LL=,RR=1e6,ans=;
while(LL<=RR){
int mid=(LL+RR)>>;
int K=query(,n,,L,R,p+mid)-query(,n,,L,R,p-mid-);
if(K>=k) {RR=mid-;ans=mid;}
else LL=mid+;
}
printf("%d\n",ans);
T=ans;
}
}
return ;
}

最新文章

  1. 项目实现不同环境不同配置文件-maven profile
  2. 模板短信接口调用java,pythoy版(二) 阿里大于
  3. linux原始套接字(1)-arp请求与接收
  4. 【leetcode】 Permutation Sequence (middle)
  5. Photoshop 使用曲线
  6. 提示错误#165 too few argument in function call
  7. VCC_VID_VTT等的含义
  8. 中文字符集编码Unicode ,gb2312 , cp936 ,GBK,GB18030
  9. linux(centos)如何查看文件夹大小
  10. 【转】PFILE和SPFILE介绍
  11. MVC 校验
  12. [转载]python 详解re模块
  13. Python字符串和日期相互转换的方法
  14. Java Web 高性能开发,第 2 部分: 前端的高性能
  15. Android Studio 使用Toast
  16. Vue基础进阶 之 实例方法--生命周期
  17. noip第17课资料
  18. Linux内核分析作业第六周
  19. Linux与Windows中的UTC时间
  20. 10 个超炫绘制图表图形的 Javascript 插件【转载+整理】

热门文章

  1. pg_receivewal实践
  2. 函数 FUNCTION
  3. LINUX之启动流程
  4. 08: mysql主从原理
  5. 基于TCP和UDP的socket
  6. HNUSTOJ-1257 You are my brother
  7. PHP批量导入excell表格到mysql数据库
  8. PyTorch环境配置及安装
  9. Solr安装(单机版)
  10. HeidiSQL