Gracekite's Homepage

Back

题目背景#

这是个非常经典的可持久化权值线段树入门题——静态区间第 小。

题目描述#

如题,给定 个整数构成的序列 ,将对于指定的闭区间 查询其区间内的第 小值。

输入格式#

第一行包含两个整数,分别表示序列的长度 和查询的个数 。
第二行包含 个整数,第 个整数表示序列的第 个元素 。
接下来 行每行包含三个整数 , 表示查询区间 内的第 小值。

输出格式#

对于每次询问,输出一行一个整数表示答案。

样例 #1#

样例输入 #1#

5 5
25957 6405 15770 26287 26465 
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
plaintext

样例输出 #1#

6405
15770
26287
25957
26287
plaintext

提示#

样例 1 解释#

,数列长度为 ,数列从第一项开始依次为。

  • 第一次查询为 区间内的第一小值,即为 。
  • 第二次查询为 区间内的第一小值,即为 。
  • 第三次查询为 区间内的第一小值,即为 。
  • 第四次查询为 区间内的第二小值,即为 。
  • 第五次查询为 区间内的第一小值,即为 。

数据规模与约定#

  • 对于 的数据,满足 。
  • 对于 的数据,满足 。
  • 对于 的数据,满足 。
  • 对于 的数据,满足 ,,,。

AC Code#

注意亿些细节:

  1. 数据规模:

    struct node{
         int lc;
         int rc;
         int val;
     }tr[40000005];
     int root[200005],val[200005];
    cpp

    初始简述需要开个节点。有次插入,每次插入最多增加个节点。 总共节点数为,约为倍;

  2. 查询

    int query(int l_pos,int r_pos,int l,int r,int rank){
         if(l==r)return l;
         int mid = (l+r)>>1;
         int s = tr[tr[r_pos].lc].val-tr[tr[l_pos].lc].val;//要判断是当前节点左儿子的情况
         if(s>=rank) return query(tr[l_pos].lc,tr[r_pos].lc,l,mid,rank);
         else return query(tr[l_pos].rc,tr[r_pos].rc,mid+1,r,rank-s);
     }
    cpp
  3. 输出

    for(int i = 1,x,y,z;i<=n;i++){
         x=read(),y=read(),z=read();
         cout<<a[query(root[x-1],root[y],1,maxn,z)-1]<<endl;//是x,y所在版本的根导入函数,由于vector a数据从0开始,
     }
    cpp
可持久化线段树
https://betteroier.github.io/blog/%E5%8F%AF%E6%8C%81%E4%B9%85%E5%8C%96%E7%BA%BF%E6%AE%B5%E6%A0%91
Author Yuxuan Zheng
Published at July 23, 2023