洛谷P3834题解
若想要深入学习主席树,传送门。
Description:
给定数列 \(\{a_n\}\) ,求闭区间 \([l,r]\) 的第 \(k\) 小的数。
Method:
先对数据进行离散化,然后按照权值建立线段树。
若要寻找 \([1,p]\) 的第 \(k\) 小,则从根节点开始处理。定义\(Son_{left}\) 表示左儿子的集合,\(Son_{right}\) 表示右儿子的集合。若 \(|Son_{left}|\ge k\) 时,说明第\(k\)小的数在左子树中,以左儿子为新的根向下递归更新,寻找左子树中第 \(k\) 小的数;反之,说明第\(k\)小的数在右子树中,以左儿子为新的根向下递归更新,寻找左子树中第 \(k-|Son_{left}|\) 小的数。
拓展一下,我们先预处理建树,得到 \(n+1\) 个版本的线段树(包括初始的线段树),编号为 \(0 \sim n\) 。
前文提到过,主席树满足前缀和查询的思想,故我们要求 \([l,r]\) 的第 \(k\) 小值,即可用sum[r]-sum[l-1]。
Code:
#include<bits/stdc++.h>
#define int long long
#define Maxn 200010
using namespace std;
inline void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
int n,m;
struct Segtree
{
    int ls,rs,sum;
}tree[Maxn<<5];
int rt[Maxn];
int a[Maxn],ins[Maxn];
int len,tot=0;
inline void Init(){tot=0;}
inline int getid(const int &x)
{
    return lower_bound(ins+1,ins+len+1,x)-ins;
}
inline void pushup(int rt)
{
    tree[rt].sum=tree[tree[rt].ls].sum+tree[tree[rt].rs].sum;
}
inline int build(int l,int r)
{
    int rt=++tot;
    if(l==r)
    {
        tree[rt].sum=0;
        return rt;
    }
    int mid=(l+r)/2;
    tree[rt].ls=build(l,mid);
    tree[rt].rs=build(mid+1,r);
    pushup(rt);
    return rt;
}
int update(int k,int l,int r,int root,int val)
{
    int rt=++tot;
    tree[rt]=tree[root];
    if(l==k&&r==k)
    {
        tree[rt].sum+=val;
        return rt;
    }
    int mid=(l+r)/2;
    if(k<=mid) tree[rt].ls=update(k,l,mid,tree[rt].ls,val);
    else tree[rt].rs=update(k,mid+1,r,tree[rt].rs,val);
    pushup(rt);
    return rt;
}
int query(int u,int v,int l,int r,int k)
{
    if(l==r) return l;
    int mid=(l+r)/2,x=tree[tree[v].ls].sum-tree[tree[u].ls].sum;
    if(k<=x) return query(tree[u].ls,tree[v].ls,l,mid,k);
    else return query(tree[u].rs,tree[v].rs,mid+1,r,k-x);
}
signed main()
{
    Init();
    read(n),read(m);
    for(int i=1;i<=n;i++)
    {
        read(a[i]);
    }
    memcpy(ins,a,sizeof(ins));
    sort(ins+1,ins+n+1);
    len=unique(ins+1,ins+n+1)-ins-1;
    rt[0]=build(1,len);
    for(int i=1;i<=n;i++)
    {
        rt[i]=update(getid(a[i]),1,len,rt[i-1],1);
    }
    while(m--)
    {
        int l,r,k;
        read(l),read(r),read(k);
        printf("%lld\n",ins[query(rt[l-1],rt[r],1,len,k)]);
    }
    return 0;
}
Warning:
ls[],rs[],sum[]等数组都要乘上 \(2^5\) 。- 离散化取
lower_bound时,是最后减去0开头的地址,而不是1开头的地址。(即是lower_bound(ins+1,ins+n+1,x)-ins,而不是lower_bound(ins+1,ins+n+1,x)-ins-1) - 查询时递归右子树时查找第 \(k-|Son_{left}|\) 小,而不是 \(k\) 小。
 
洛谷P3834题解的更多相关文章
- [洛谷P3376题解]网络流(最大流)的实现算法讲解与代码
		
[洛谷P3376题解]网络流(最大流)的实现算法讲解与代码 更坏的阅读体验 定义 对于给定的一个网络,有向图中每个的边权表示可以通过的最大流量.假设出发点S水流无限大,求水流到终点T后的最大流量. 起 ...
 - 洛谷P5759题解
		
本文摘自本人洛谷博客,原文章地址:https://www.luogu.com.cn/blog/cjtb666anran/solution-p5759 \[这道题重在理解题意 \] 选手编号依次为: \ ...
 - 关于三目运算符与if语句的效率与洛谷P2704题解
		
题目描述 司令部的将军们打算在N*M的网格地图上部署他们的炮兵部队.一个N*M的地图由N行M列组成,地图的每一格可能是山地(用“H” 表示),也可能是平原(用“P”表示),如下图.在每一格平原地形上最 ...
 - c++并查集配合STL MAP的实现(洛谷P2814题解)
		
不会并查集的话请将此文与我以前写的并查集一同食用. 原题来自洛谷 原题 文字稿在此: 题目背景 现代的人对于本家族血统越来越感兴趣. 题目描述 给出充足的父子关系,请你编写程序找到某个人的最早的祖先. ...
 - 洛谷P2607题解
		
想要深入学习树形DP,请点击我的博客. 本题的DP模型同 P1352 没有上司的舞会.本题的难点在于如何把基环树DP转化为普通的树上DP. 考虑断边和换根.先找到其中的一个环,在上面随意取两个点, 断 ...
 - 「洛谷 P3834」「模板」可持久化线段树 题解报告
		
题目描述 给定n个整数构成的序列,将对于指定的闭区间查询其区间内的第k小值. 输入输出格式 输入格式 第一行包含两个正整数n,m,分别表示序列的长度和查询的个数. 第二行包含n个整数,表示这个序列各项 ...
 - 洛谷 P3834 卢卡斯定理 题解
		
题面 首先你需要知道这条定理: C(n,m)=C(n%p,m%p)*C(n/p,m/p); 这样可以递归实现: 注意坑点:是C(n+m,m),并不是C(n,m); #include <bits/ ...
 - 【刷题】洛谷 P3834 【模板】可持久化线段树 1(主席树)
		
题目背景 这是个非常经典的主席树入门题--静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输 ...
 - 【洛谷】题解 P1056 【排座椅】
		
题目链接 因为题目说输入保证会交头接耳的同学前后相邻或者左右相邻,所以一对同学要分开有且只有一条唯一的通道才能把他们分开. 于是可以吧这条通道累加到一个数组里面.应为题目要求纵列的通道和横列的通道条数 ...
 
随机推荐
- JavaScript由来
			
在互联网时代,网速还很差劲的时候,表单输入数据的合法性验证需要与服务器交换数据,从而加重了使用者的负担. 网景公司为了解决这种简单问题开发了JavaScript.在1995年2月网景公司在发布自己的浏 ...
 - ad域的那些事儿
			
先附上参考链接,有空再来整理 基础知识:https://www.cnblogs.com/cnjavahome/p/9029665.html ad域的操作:https://www.cnblogs.com ...
 - Echarts 学习系列(1)-5分钟上手ECharts
			
目录 写在前面 下载Echarts和主题 绘制一个简单的图表 写在前面 最近,在做某个项目的时候.需要使用的可视化的图表显数据.最后,选择了百度的Echarts. 下载Echarts和主题 1.获取E ...
 - C#读写修改设置调整UVC摄像头画面-清晰度
			
有时,我们需要在C#代码中对摄像头的清晰度进行读和写,并立即生效.如何实现呢? 建立基于SharpCamera的项目 首先,请根据之前的一篇博文 点击这里 中的说明,建立基于SharpCamera的摄 ...
 - ES10(2019)有哪些更新和新特性?
			
ES10新特性(2019) 行分隔符(U + 2028)和段分隔符(U + 2029)符号现在允许在字符串文字中,与JSON匹配 更加友好的 JSON.stringify 新增了Array的flat( ...
 - Solr基础理论【相关度计算】
			
一.简介 寻找匹配的文档是构建优质搜索体验的关键步骤,但这仅仅是第一步.大多数用户不愿意通过逐页翻阅搜索结果来找到想要的文档.根据一般经验,仅有10%的用户在网页搜索中有意愿继续翻阅第一页以后的搜索结 ...
 - Golang: 打印命令行参数
			
记得最早在学校机房学习 Java 时,照着书上的例子,写一个最简单 main 方法,当程序运行并在屏幕上打印出 hello world 时,内心竟有种莫名的激动,相信很多人都有这种经历吧. 不管学什么 ...
 - 详解Linux操作系统的进程
			
系统 计算机运行起来以后,就是由内核和运行在内核之上的众多进程来实现的(kernel+process) 内存分为 : 线性内存: 物理内存: 计算机的所有运行都只在内存和CPU中运行! 内核空间 ...
 - jenkins部署java项目(五)
			
一.web server安装jdk+tomcat其中jdk可以为openjdk,版本1.8 1.1 安装jdk环境 方式一:直接使用yum安装openjdk # * 方式二:本地安装在oracle官网 ...
 - Python时间模块。
			
python中时间的表示方式 unix时间戳,字符串时间,格式化时间 时间模块有,time,datetime,calendar #time模块 import time #获取本地时间戳,返回浮点数 p ...