【模板】可持久化线段树 2
题目背景
这是个非常经典的可持久化权值线段树入门题——静态区间第 \(k\) 小。
数据已经过加强,请使用可持久化权值线段树。同时请注意常数优化。
题目描述
如题,给定 \(n\) 个整数构成的序列 \(a\),将对于指定的闭区间 \([l, r]\) 查询其区间内的第 \(k\) 小值。
输入格式
第一行包含两个整数,分别表示序列的长度 \(n\) 和查询的个数 \(m\)。
第二行包含 \(n\) 个整数,第 \(i\) 个整数表示序列的第 \(i\) 个元素 \(a_i\)。
接下来 \(m\) 行每行包含三个整数 $ l, r, k$ , 表示查询区间 \([l, r]\) 内的第 \(k\) 小值。
输出格式
对于每次询问,输出一行一个整数表示答案。
样例 #1
样例输入 #1
5 5
25957 6405 15770 26287 26465
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
样例输出 #1
6405
15770
26287
25957
26287
提示
样例 1 解释
\(n=5\),数列长度为 \(5\),数列从第一项开始依次为\(\{25957, 6405, 15770, 26287, 26465\}\)。
- 第一次查询为 \([2, 2]\) 区间内的第一小值,即为 \(6405\)。
- 第二次查询为 \([3, 4]\) 区间内的第一小值,即为 \(15770\)。
- 第三次查询为 \([4, 5]\) 区间内的第一小值,即为 \(26287\)。
- 第四次查询为 \([1, 2]\) 区间内的第二小值,即为 \(25957\)。
- 第五次查询为 \([4, 4]\) 区间内的第一小值,即为 \(26287\)。
数据规模与约定
- 对于 \(20\%\) 的数据,满足 \(1 \leq n,m \leq 10\)。
- 对于 \(50\%\) 的数据,满足 \(1 \leq n,m \leq 10^3\)。
- 对于 \(80\%\) 的数据,满足 \(1 \leq n,m \leq 10^5\)。
- 对于 \(100\%\) 的数据,满足 \(1 \leq n,m \leq 2\times 10^5\),\(|a_i| \leq 10^9\),\(1 \leq l \leq r \leq n\),\(1 \leq k \leq r - l + 1\)。
先看这篇博客
P3919 【模板】可持久化线段树 1(可持久化数组) - 沙野博士 - 博客园 (cnblogs.com)
本题要求查询区间第k小,也就是对于给定区间[l,r] ,将其中的数按从小到大排序,找到其中第k个元素。
由持久化线段树1可知,我们可以用线段树维护一个可持久化数组,这道题要维护的数组就是这些元素的桶这个数组。按位置每一个位置就是一个历史版本。
实现过程中,最好先建一个完整的空的线段树,省去判断指针是否为空的麻烦。
/*
P3834 【模板】可持久化线段树 2
*/
#include<algorithm>
#include<iostream>
using namespace std;
const int N = 2e5+10;
inline int read()
{
register char c = getchar(); register int x = 0 , f = 0;
while(c < '0' || c > '9') f |= c == '-' , c = getchar();
while(c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0' , c = getchar();
return f ? -x : x;
}
int n;
int A[N] , B[N];
struct node{
node *ls , *rs;
int size;
node(int size = 0) : ls(NULL) , rs(NULL) , size(size){}
}*rot[N];
void Init()
{
//int *B = new int [n + 1];
for(int i = 1 ; i <= n ; ++i) B[i] = A[i];
sort(B + 1 , B + 1 + n);
for(int i = 1 ; i <= n ; ++i) A[i] = lower_bound(B + 1 , B + 1 + n , A[i]) - B;
}
void build(node *&rt , int l , int r)
{
rt = new node;
if(l == r) return ;
int mid = (l + r) >> 1;
build(rt->ls , l , mid);
build(rt->rs , mid+1 , r);
}
void modify(node *&rt , node *lst , int l , int r , int pos)
{
rt = new node; rt->size = lst->size + 1;
if(l == r) return ;
int mid = (l + r) >> 1;
if(pos <= mid)
rt->rs = lst->rs , modify(rt->ls , lst->ls , l , mid , pos);
else
rt->ls = lst->ls , modify(rt->rs , lst->rs , mid+1 , r , pos);
}
int query(node *L , node *R , int l , int r , int k)
{
if(l == r) return l;
int num = (R->ls ? R->ls->size : 0) - (L->ls ? L->ls->size : 0);
int mid = (l + r) >> 1;
if(k <= num)
return query(L->ls , R->ls , l , mid , k);
else
return query(L->rs , R->rs , mid+1 , r , k - num);
}
int main()
{
int m , l , r , k;
n = read(); m = read();
for(int i = 1 ; i <= n ; ++i)
A[i] = read();
Init();
// cout << "YES" << '\n';
build(rot[0] , 1 , n);
// cout << "YES" << '\n';
for(int i = 1 ; i <= n ; ++i)
modify(rot[i] , rot[i-1] , 1 , n , A[i]);
// cout << "YES" << '\n';
while(m--)
{
l = read(); r = read(); k = read();
printf("%d\n" , B[query(rot[l-1] , rot[r] , 1 , n , k)]);
}
return 0;
}
标签:rt,leq,int,线段,mid,P3834,ls,模板
From: https://www.cnblogs.com/sybs5968QAQ/p/16938124.html