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 ...
随机推荐
- 小白学Java:RandomAccessFile
目录 小白学Java:RandomAccessFile 概述 继承与实现 构造器 模式设置 文件指针 操作数据 读取数据 read(byte b[])与read() 追加数据 插入数据 小白学Java ...
- 【阿里云IoT+YF3300】12.阿里云IoT Studio入门介绍
阿里云IoT Studio是针对物联网场景提供的生产力工具,可覆盖各个物联网行业核心应用场景,帮助您高效经济地完成设备.服务及应用开发.物联网开发服务提供了移动可视化开发.Web可视化开发.服务开发与 ...
- java线程池及创建多少线程合适
java线程池 1.以下是ThreadPoolExecutor参数完备构造方法: public ThreadPoolExecutor(int corePoolSize,int maximumPoolS ...
- input输入框联想功能
一直想找一个可以连接后台,可以根据后台内容的input输入框,可以实现联想功能,网上找到一个简单的静态页面的输入框联想,经过一番修改之后终于可以实现读取自己定义的数组的联想了,其实也比较简单就是格式的 ...
- 讲一下java,c语言,c+和c++都是干嘛的,他们运行的软件都是哪些
讲一下java,c语言,c+和c++都是干嘛的,他们运行的软件都是哪些 都是用于开发软件的,用于不同的方面.比如,淘宝的后台,是java做的.而腾讯的qq的后台服务器,是c和c++的.暴雪游戏的后台服 ...
- 如何快速查看Linux日志?
因为在生产环境会遇到很多问题,那么最快的定位方式莫过于去看日志,我们都知道服务器每天会产生大量的日志,那么如何快速的定位也就是最关键的. 本文介绍六种查看日志的命令:tail.head.cat.mor ...
- 文件传输基础----Java IO流
编码问题 一个很著名的奇怪现象:当你在 windows 的记事本里新建一个文件,输入"联通"两个字之后,保存,关闭,然后再次打开,你会发现这两个字已经消失了,代之的是几个乱码!呵呵 ...
- Java7循环结构综合练习
import java.util.Scanner; public class jh_01_学员操作_选择游戏 { public static void main(String[] args) { Sc ...
- Nginx 部署及配置
Tengine + Luajit2 系统账号及环境配置 $ sudo useradd -g 100 -u 200 user_00 $ sudo groupadd -g 300 www $ sudo u ...
- 给Hangfire的webjob增加callback和动态判断返回结果功能设计
背景介绍 通常业务中需要用到定时执行功能,我用hangfire搭建了一个调度服务,这个调度服务是独立于业务逻辑的,具体可以参考文章:https://github.com/yuzd/Hangfire.H ...