HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)
题意:给一个数组,每次给 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 ;
}
HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)的更多相关文章
- 【bzoj3065】带插入区间K小值 替罪羊树套权值线段树
题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出 ...
- 【BZOJ3065】带插入区间K小值 替罪羊树+权值线段树
[BZOJ3065]带插入区间K小值 Description 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理 ...
- 3065: 带插入区间K小值_树套树_替罪羊树_权值线段树
经过周六一天,周一3个小时的晚自习,周二2个小时的疯狂debug,终于凭借自己切掉了这道树套树题. Code: #include <cstdio> #include <algorit ...
- BZOJ 3110 ZJOI 2013 K大数查询 树套树(权值线段树套区间线段树)
题目大意:有一些位置.这些位置上能够放若干个数字. 如今有两种操作. 1.在区间l到r上加入一个数字x 2.求出l到r上的第k大的数字是什么 思路:这样的题一看就是树套树,关键是怎么套,怎么写.(话说 ...
- 动态求区间K大值(权值线段树)
我们知道我们可以通过主席树来维护静态区间第K大值.我们又知道主席树满足可加性,所以我们可以用树状数组来维护主席树,树状数组的每一个节点都可以开一颗主席树,然后一起做. 我们注意到树状数组的每一棵树都和 ...
- BZOJ3110[Zjoi2013]K大数查询——权值线段树套线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是 ...
- 【bzoj3110】[Zjoi2013]K大数查询 权值线段树套区间线段树
题目描述 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c.如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数 ...
- 区间第k大问题 权值线段树 hdu 5249
先说下权值线段树的概念吧 权值平均树 就是指区间维护值为这个区间内点出现次数和的线段树 用这个加权线段树 解决第k大问题就很方便了 int query(int l,int r,int rt,int k ...
- [BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树)
[BZOJ 3110] [luogu 3332] [ZJOI 2013]k大数查询(权值线段树套线段树) 题面 原题面有点歧义,不过从样例可以看出来真正的意思 有n个位置,每个位置可以看做一个集合. ...
随机推荐
- Nginx 的方向代理及配置
最近有打算研读nginx源代码,看到网上介绍nginx可以作为一个反向代理服务器完成负载均衡.所以搜罗了一些关于反向代理服务器的内容,整理综合. 一 概述 反向代理(Reverse Proxy)方式 ...
- 获取kafka最新offset-java
之前笔者曾经写过通过scala的方式获取kafka最新的offset 但是大多数的情况我们需要使用java的方式进行获取最新offset scala的方式可以参考: http://www.cnblog ...
- [2019多校联考(Round 6 T3)]脱单计划 (费用流)
[2019多校联考(Round 6 T3)]脱单计划 (费用流) 题面 你是一家相亲机构的策划总监,在一次相亲活动中,有 n 个小区的若干男士和 n个小区的若干女士报名了这次活动,你需要将这些参与者两 ...
- 「POI2010」反对称 Antisymmetry (manacher算法)
# 2452. 「POI2010」反对称 Antisymmetry [题目描述] 对于一个 $0/1$ 字符串,如果将这个字符串 $0$ 和 $1$ 取反后,再将整个串反过来和原串一样,就称作「反对称 ...
- JS 的 Array 和String 常混淆方法
知识一: 1.slice() 提取字符串 slice[ start, end) 如果参数为负数,表示从尾部开始算起. 2.subString() 提取字符串 3.subStr() 提取字符串 subS ...
- javaweb新手学习之Tomcat
一.Tomcat服务器常见启动问题: (1).Java_home环境变量,由于tomcat服务器的bin目录中的一些jar文件必须使用到java类库,所以必须先配置Java_home环境变量. (2) ...
- c/c++基础篇之数据类型转换
C/C++常见的数据类型转换 1. 常见的单类基本类型转换 (1)强制类型转换 如: int a=(int)(9.87) 结果a=9 char c=(char)(97) 结果为c=’a’ ...
- ubuntu(linux)如何安装nginx?
之前要在linux下面安装nginx,弄了半天,终于搞定了,下面给大家详细一下安装流程及安装报错解决方案: 安装共分为5步搞定: 1.进入src目录(下载存放目录) cd /usr/loca ...
- Cannot find the declaration of element 'ehcache'.
ehchahe.xml中报错: Cannot find the declaration of element 'ehcache'. 由于 <?xml version="1.0" ...
- 打包组件assembly之package.xml
形如: <assembly> <id>deploy</id> <formats> <format>zip</format> &l ...