luogu3834模板可持久化线段树 2(主席树),静态区间第K小值
Posted 小哈里
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了luogu3834模板可持久化线段树 2(主席树),静态区间第K小值相关的知识,希望对你有一定的参考价值。
problem
solution
题目:有n个数,多次询问一个区间[L,R]中第k小的值是多少。
思路:
- 查询[1,n]中的第k小值:
- 先对数据进行离散化,然后按值域建立线段树,线段树中维护某个值域中的元素个数, 在线段树的 每个结点上记录这一个值域中的元素个数 ,
- 那么要寻找第k小值,从根结点开始处理,若左儿子中表示的元素个数大于等于k,那么我们递归的处理左儿子,寻找左儿子中第k小的数,若左儿子中的元素个数小于k,那么第k小的数在右儿子中,我们寻找右儿子中第k-(左儿子中的元素数)小的数。
- 查询区间[L,R]中的第K小值:
- 我们按照从1到n的顺序依次将数据插入可持久化的线段树中,将会得到n+1个版本的值域线段树(包括初始化的版本),将其编号为0~n。可以发现所有版本的线段树都拥有相同的结构,它们同一个位置上的结点的含义都相同。
- 考虑第i个版本的线段树的结点P,P中储存的值 表示[1,i]这个区间中,P结点的值域中所含的元素个数 ;假设我们知道了[1,R]区间中P结点的值域中所含的元素个数,也知道[1,L-1]区间中P结点的值域中所包含的元素个数,显然用第一个个数减去第二个个数,就可以得到[L,R]区间中的元素个数(即该区间的值域线段树)。
- 因此我们对于一个查询[L,R],同步考虑两个根root[L-1]与root[R],用它们同一个位置的结点的差值就表示了区间[L,R]中的元素个数,利用这个性质,从两个根节点,向左右儿子中递归的查找第k小数即可。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
int a[maxn], b[maxn];
int rt[maxn], lch[maxn<<5], rch[maxn<<5], sum[maxn<<5], tot;//主席树
void build(int &p, int l, int r){
p = ++tot;
if(l==r)return ;
int mid = (l+r)>>1;
build(lch[p], l, mid);
build(rch[p], mid+1, r);
}
int update(int p, int l, int r, int x){ //b[x]+=1;
int np = ++tot;
lch[np]=lch[p], rch[np] = rch[p], sum[np] = sum[p]+1;
if(l==r)return np;
int mid = (l+r)>>1;
if(x<=mid)lch[np] = update(lch[np], l, mid, x);
else rch[np] = update(rch[np], mid+1, r, x);
return np;
}
int query(int u, int v, int l, int r, int k){
int ans, mid=(l+r>>1), x=sum[lch[v]]-sum[lch[u]];
if(l==r)return l;
if(x>=k)ans = query(lch[u], lch[v], l, mid, k);
else ans = query(rch[u], rch[v], mid+1, r, k-x);
return ans;
}
int main(){
int n, q; cin>>n>>q;
for(int i = 1; i <= n; i++)cin>>a[i], b[i]=a[i];
sort(b+1,b+n+1);
int m = unique(b+1,b+n+1)-b-1;
build(rt[0], 1, m); //用离散化后的数据建立初始的值域线段树,区间加维护每个元素(位置)的出现次数
for(int i = 1; i <= n; i++){
int p = lower_bound(b+1,b+m+1, a[i])-b;//查询a[i]离散化后对应的值
rt[i] = update(rt[i-1], 1, m, p); //建立第i个版本的值域线段树,维护[1,i]时,每个区间的元素个数
}
while(q--){
int l, r, k; cin>>l>>r>>k;
int ans = query(rt[l-1],rt[r],1,m,k); //查询用第r个版本和第l-1个版本之间值域差值查
cout<<b[ans]<<"\\n"; //返回离散化对应的值
}
return 0;
}
以上是关于luogu3834模板可持久化线段树 2(主席树),静态区间第K小值的主要内容,如果未能解决你的问题,请参考以下文章
luogu3834模板可持久化线段树 2(主席树),静态区间第K小值