luogu P3834 【模板】可持久化线段树 1(主席树) 查询区间 [l, r] 内的第 k 小/大值
————————————————
版权声明:本文为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 小/大值的更多相关文章
- 洛谷P3834 [模板]可持久化线段树1(主席树) [主席树]
题目传送门 可持久化线段树1(主席树) 题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定 ...
- 【Luogu P3834】可持久化线段树(主席树)
Luogu P3834 可持久化数据结构就是支持在历史版本上进行查询和修改操作的数据结构. 主席树就是对线段树的改进,使之可持久化. 前置知识:动态开点线段树 我们利用权值(值域)线段树统计区间内的数 ...
- 【洛谷 P3834】 可持久化线段树1(主席树)
题目链接 主席树=可持久化权值线段树. 如果你不会可持久化线段树,请右转 如果你不会权值线段树,请自行脑补,就是线段树维护值域里有多少个数出现. 可持久化线段树是支持查询历史版本的. 我们对每个数都进 ...
- luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)
luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...
- P3919 【模板】可持久化数组 -初步探究主席树
本篇blog主要是给自己(大家)看的. 感谢longlongzhu123奆佬(此人初二LCT)的指点,使本蒟蒻可以快速开始主席树入门. what is 主席树? $ $主席树这个名字只不 ...
- 归并树 划分树 可持久化线段树(主席树) 入门题 hdu 2665
如果题目给出1e5的数据范围,,以前只会用n*log(n)的方法去想 今天学了一下两三种n*n*log(n)的数据结构 他们就是大名鼎鼎的 归并树 划分树 主席树,,,, 首先来说两个问题,,区间第k ...
- 可持久化线段树(主席树)快速简洁教程 图文并茂 保证学会。kth number例题
如果学不会也不要打我. 假设你会线段树 开始! --- 主席树也叫可持久化线段树 顾名思义,它能够保存线段树在每个时刻的版本. 什么叫每个时刻的版本?你可能对一棵普通线段树进行各种修改,这每种样子就是 ...
- 可持久化线段树(主席树)——静态区间第k大
主席树基本操作:静态区间第k大 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=2e5+, ...
- 【bzoj3524】【Poi2014】【Couriers】可持久化线段树(主席树)水题
[pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=62485671 向大(hei)佬(e)势力学(di ...
随机推荐
- Android教程2020 - RecyclerView实际使用
示例,用RecyclerView的item做出一个列表. Android教程2020 - 系列总览 本文链接 前面我们已经知道如何用RecyclerView显示一列数据.这里我们做出一个具体的例子.尽 ...
- mybatis typeAlias (别名)说明
...
- mysql 基本常用语句
1.展示当前数据库 所有表名(前提必须进入数据库,进入数据库语句:[use 数据库名;])mysql> show create table 表名; 2.看mysql支持哪些存储引擎:mysql& ...
- Git 初级使用 windows & Ubuntu
目的:有一段代码要进行几个人同时维护,但是传来传去不方便,所以希望在github上实现,前提是每台机器都有git 在github 上新建一个项目 然后会看到,大体上就按这执行就可以 在Windows系 ...
- 基于HTTPS的接口测试——nginx配置SSL
目录 基于HTTPS的接口测试--nginx配置SSL 1. 背景 2. 所需环境与域名备案解析 2.1 云服务器 2.2 域名 2.3 SSL证书 2.4 网站备案 2.5 域名解析 3.nginx ...
- C语言学习笔记--void
void真正发挥的作用在于: (1) 对函数返回的限定: (2) 对函数参数的限定. 先给一个例子 定义函数返回值 函数名(参数1,参数2,参数3,.......){内容}int sum(int a ...
- constrainlayout布局
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/r ...
- yukongDSRM账户安全防护
一.DSRM简介 1.DSRM(Diretcory Service Restore Mode,目录服务恢复模式)是windows域环境中域控制器的安全模式启动选项.域控制器的本地管理员账户也就是DSR ...
- 【WPF学习】第四十五章 可视化对象
前面几章介绍了处理适量适中的图形内容的最佳方法.通过使用几何图形.图画和路径,可以降低2D图形的开销.即使正在使用复杂的具有分层效果的组合形状和渐变画刷,这种方法也仍然能够正常得很好. 然而,这样设计 ...
- centos下利用phantomjs来完成网站页面快照截图
最近研究了下phantomjs,感觉还是非常不错的. 首先到官网下载一个源码包 http://phantomjs.org/download.html 点击源码包下载如图: 然后在linux下将必要的一 ...