————————————————
版权声明:本文为CSDN博主「ModestCoder_」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ModestCoder_/article/details/90139481

//主席树
//难以处理区间修改操作,很难处理懒标记
//l,r代表左右子节点的下标
//cnt表示当前区间中一共多少个数 //离散化
//在数值上建立线段树,维护每个数值区间中一共多少个数
//
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = ;
int n, m;
int a[N];
vector<int> nums;
struct Node
{
//左儿子和右儿子的
//左边都是比l+r>>1小的
//右边都是大的
int l, r;
//区间里一共多少个数
int cnt;
}tr[N << ];
//根节点 树里可用节点的下标
int root[N << ], idx;
//求离散化之后的值
int find(int x)
{
return lower_bound(nums.begin(), nums.end(), x) - nums.begin();
} //建树,原始的,没插入数字的树
int build(int l, int r)
{
//建立新的
int p = ++ idx;
//如果是叶节点
if (l == r)
return p;
//左右儿子
int mid = l + r >> ;
tr[p].l = build(l, mid), tr[p].r = build(mid + , r);
return p;
}
//原来的根节点,左右边界, 插入的位置(原来的数字离散化后的排名)
// 0,nums.size()-1,
int insert(int p, int l, int r, int x)
{
//从0号点开始查找
//root的cnt表示的是1到num.size()-1之间数字的个数
//所以root这个点肯定会变化
//所以要开新的点
int q = ++ idx;
//在没有找到之前
//先赋值过来,上一个版本的根节点
//
tr[q] = tr[p];
//如果是叶节点,找到要更新的店
//也就是找到x这个位置了
//就是去找要找插入的点
if (l == r)
{
//新点cnt++
tr[q].cnt ++ ;
return q;
}
//如果没有找到要更新的点
//当前点往下递归,
int mid = l + r >> ;
//递归
//更新沿途的点
if (x <= mid)
tr[q].l = insert(tr[p].l, l, mid, x);
else
tr[q].r = insert(tr[p].r, mid + , r, x);
//左右儿子的cnt的和
tr[q].cnt = tr[tr[q].l].cnt + tr[tr[q].r].cnt;
return q;
} int query(int q, int p, int l, int r, int k)
{
//如果到叶节点了 ,就返回
if (l == r)
return r;
//左区间表示
//1到 tr[q].l中数字的个数- 1到tr[p].l中数字的个数
//这些数字都是属于 要 查询的区间中的数字
int cnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
//中点,左右儿子的中点
int mid = l + r >> ;
//如果k<=cnt
//也就是要查询的区间(下标)中的数字插入到左半边的数字大于等于k
//那么答案对应的离散化之后的坐标就一定在左边
if (k <= cnt)
return query(tr[q].l, tr[p].l, l, mid, k);
//或者都在右边,这里k要更新为k-cnt,要除去左半边的
else
return query(tr[q].r, tr[p].r, mid + , r, k - cnt);
}
int main()
{
scanf("%d%d", &n, &m);
//读入数据
for (int i = ; i <= n; i ++ )
{
scanf("%d", &a[i]);
nums.push_back(a[i]);
}
//离散化
//会排序
sort(nums.begin(), nums.end());
nums.erase(unique(nums.begin(), nums.end()), nums.end());
//第一个版本的线段树,是root[0]
root[] = build(, nums.size() - );
for (int i = ; i <= n; i ++ )
//第i个版本的线段树
//是和i-1版本的线段树比较,左右边界是0到 nums.size() - 1,在find(a[i])这个位置加1
// 对应a[i]的离散值
root[i] = insert(root[i - ], , nums.size() - , find(a[i])); while (m -- )
{
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
//要返回离散化前的值
printf("%d\n", nums[query(root[r], root[l - ], , nums.size() - , k)]);
}
return ;
}

luogu P3834 【模板】可持久化线段树 1(主席树) 查询区间 [l, r] 内的第 k 小/大值的更多相关文章

  1. 洛谷P3834 [模板]可持久化线段树1(主席树) [主席树]

    题目传送门 可持久化线段树1(主席树) 题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定 ...

  2. 【Luogu P3834】可持久化线段树(主席树)

    Luogu P3834 可持久化数据结构就是支持在历史版本上进行查询和修改操作的数据结构. 主席树就是对线段树的改进,使之可持久化. 前置知识:动态开点线段树 我们利用权值(值域)线段树统计区间内的数 ...

  3. 【洛谷 P3834】 可持久化线段树1(主席树)

    题目链接 主席树=可持久化权值线段树. 如果你不会可持久化线段树,请右转 如果你不会权值线段树,请自行脑补,就是线段树维护值域里有多少个数出现. 可持久化线段树是支持查询历史版本的. 我们对每个数都进 ...

  4. luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

    luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...

  5. P3919 【模板】可持久化数组 -初步探究主席树

    本篇blog主要是给自己(大家)看的. 感谢longlongzhu123奆佬(此人初二LCT)的指点,使本蒟蒻可以快速开始主席树入门. what is 主席树? $        $主席树这个名字只不 ...

  6. 归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665

    如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k ...

  7. 可持久化线段树(主席树)快速简洁教程 图文并茂 保证学会。kth number例题

    如果学不会也不要打我. 假设你会线段树 开始! --- 主席树也叫可持久化线段树 顾名思义,它能够保存线段树在每个时刻的版本. 什么叫每个时刻的版本?你可能对一棵普通线段树进行各种修改,这每种样子就是 ...

  8. 可持久化线段树(主席树)——静态区间第k大

    主席树基本操作:静态区间第k大 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=2e5+, ...

  9. 【bzoj3524】【Poi2014】【Couriers】可持久化线段树(主席树)水题

    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62485671 向大(hei)佬(e)势力学(di ...

随机推荐

  1. git--->Git中.gitignore配置

    Git中.gitignore文件不起作用的解决以及Git中的忽略规则介绍 在Studio里使用Git管理代码的过程中,可以修改.gitignore文件中的标示的方法来忽略开发者想忽略掉的文件或目录,如 ...

  2. SpringBoot使用JMS(activeMQ)的两种方式 队列消息、订阅/发布

    刚好最近同事问我activemq的问题刚接触所以分不清,前段时间刚好项目中有用到,所以稍微整理了一下,仅用于使用 1.下载ActiveMQ 地址:http://activemq.apache.org/ ...

  3. PAT乙级(Basic Level)真题,福尔摩斯的约会

    题目描述 大侦探福尔摩斯接到一张奇怪的字条:“我们约会吧! 3485djDkxh4hhGE 2984akDfkkkkggEdsb s&hgsfdk d&Hyscvnm”.大侦探很快就明 ...

  4. 文件系统(02):基于SpringBoot框架,管理Xml和CSV文件类型

    本文源码:GitHub·点这里 || GitEE·点这里 一.文档类型简介 1.XML文档 XML是可扩展标记语言,是一种用于标记电子文件使其具有结构性的标记语言.标记指计算机所能理解的信息符号,通过 ...

  5. 开源虚拟机Bochs安装以及踩坑

    因为想要写一个简单的操作系统,所以需要安装虚拟机来模拟出硬件,VMware不适合这个场景,因为会使用硬件级别的虚拟化,而bochs这个开源虚拟机,是用软件虚拟了所有的硬件,所以调试可以做到非常细的粒度 ...

  6. 机器学习(ML)七之模型选择、欠拟合和过拟合

    训练误差和泛化误差 需要区分训练误差(training error)和泛化误差(generalization error).前者指模型在训练数据集上表现出的误差,后者指模型在任意一个测试数据样本上表现 ...

  7. 大牛给的ACM进阶建议

    转:https://blog.csdn.net/mmy1996/article/details/56011084 来自知乎 在他后面的回答中发现 不用IDE ,修炼内功挺好的,不过他和我的以前的那种 ...

  8. Go语言实现:【剑指offer】数组中只出现一次的数字

    该题目来源于牛客网<剑指offer>专题. 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 正常能想到哈希表来处理,但此题考查的是异或的知识, ...

  9. 【C++】C++程序加载lib静态库

    使用Visual Studio 编写C++程序有几种配置lib的方法,以下是在代码中加载lib文件的方法: 在项目所在目录下创建文件夹lib,将lib文件此路径下,包括Debug和Release两种模 ...

  10. Hapi+MySql项目实战环境初始化(一)

    因为项目要求特殊的原因,公司要求使用Nodejs+HApi(纯英文的API)+Mysql构建新的项目.网上找了一堆资料,看了半天一脸懵逼.结论就是:版本的差异,资料国内几乎都是旧的17年前的了.根据资 ...