————————————————
版权声明:本文为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. Redis 中的数据持久化策略(AOF)

    上一篇文章,我们讲的是 Redis 的一种基于内存快照的持久化存储策略 RDB,本质上他就是让 redis fork 出一个子进程遍历我们所有数据库中的字典,进行磁盘文件的写入. 但其实这种方式是有缺 ...

  2. 搭建本地测试es集群

    需求 在本地搭建es+kibana+elasticsearch-head 搭建环境 mac本地,使用docker+docker-compose 方式搭建 设置docker 内存8G 搭建es和es+h ...

  3. springboot mybatis 多数据源配置支持切换以及一些坑

    一 添加每个数据源的config配置,单个直接默认,多个需要显示写出来 @Configuration @MapperScan(basePackages ="com.zhuzher.*.map ...

  4. STL中的vector 和list

    参考书目:visual c++ 入门经典 第七版 Ivor Horton著 第十章 认识两个容器:vector和list 容器:是STL(Standard Template Library 标准模板库 ...

  5. Mplayer另类在线播放影音文件技巧【转】

    http://www.linuxsir.org/bbs/showthread.php?t=254467 本文介绍的Mplayer在线播放的方法,不是指在浏览器中安装Mplayer插件这种方法,而是在命 ...

  6. Altium Designer 14安装破解

    Altium Designer 14简称AD14,是一款专业的PCB设计软件,利用他可以计出专业的PCB元件.Altium Designer 14.3.10是目前的最新版本. Altium Desig ...

  7. java3选择结构一

    1 public class jh_01_为什么需要if选择结构 { 2 /* 3 * 让它有条件性的去执行某些内容. 4 * System.out.println(2); 5 * 把你要控制的内容放 ...

  8. 基于 Google-S2 的地理相册服务实现及应用

    马蜂窝技术原创内容,更多干货请关注公众号:mfwtech 随着智能手机存储容量的增大,以及相册备份技术的普及,我们可以随时随地用手机影像记录生活,在手机中存储几千张甚至上万张照片已经是很常见的事情.但 ...

  9. 异步并发利器:实际项目中使用CompletionService提升系统性能的一次实践

    场景 随着互联网应用的深入,很多传统行业也都需要接入到互联网.我们公司也是这样,保险核心需要和很多保险中介对接,比如阿里.京东等等.这些公司对于接口服务的性能有些比较高的要求,传统的核心无法满足要求, ...

  10. python学习(5)写一个二分算法的程序

    把之前学习的做一个小结.之前看二分查找法,只能是似而非地看懂大概.现在用这么多天的知识积累已经可以自己写了. 而且在算法书的基础上,把需要找的数字做一个人机互动操作. 另外,初步接触到了 __name ...