————————————————
版权声明:本文为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. JVM源码分析-JVM源码编译与调试

    要分析JVM的源码,结合资料直接阅读是一种方式,但是遇到一些想不通的场景,必须要结合调试,查看执行路径以及参数具体的值,才能搞得明白.所以我们先来把JVM的源码进行编译,并能够使用GDB进行调试. 编 ...

  2. httpClient爬虫

    package httpClient.client; import java.io.File; import java.io.IOException; import java.io.InputStre ...

  3. Shell环境变量文件

    /etc/profile 系统级的初始化环境变量文件,由登录Shell调用执行 /etc/profile.d 当/etc/profile运行时,会调用该目录下的一些脚本 /etc/bashrc 每个交 ...

  4. 不停机替换线上代码? 你没听错,Arthas它能做到

    写在前边 有没有这样一种感受,自己写的代码在开发.测试环境跑的稳得一笔,可一到线上就抽风,不是缺这个就是少那个反正就是一顿报错,线上调试代码又很麻烦,让人头疼得很.阿里巴巴出了一款名叫Arthas的工 ...

  5. Sea.js 手册与文档

    Sea.js 手册与文档 首页 | 索引 目录 何为 CommonJS 何为 CommonJS 模块 为何封装模块 何为 CommonJS? CommonJS 是一个有志于构建 JavaScript ...

  6. java刷题(1-5)

    第一题:在一个数组中找出三个数相加之和为0,且不重复的集合 import java.lang.reflect.Array; import java.security.PublicKey; import ...

  7. webpack入门系列1

    一.什么是webpack?为什么要使用它? Webpack 是一个前端资源加载/打包工具.它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源. 为什么我们要使用它呢?因 ...

  8. Django自动化测试平台项目案例

    引言 在项目组待了近半年时间,根据自己的感受和体验,做了一个辅助测试的工具(数据预报平台),主要目的是针对目前项目接口文档缺失,自动化预报脚本无法可视化,资源循环利用,统一管理化. 业务背景 我们项目 ...

  9. 开源镜像站-Android镜像

    mirrors.neusoft.edu.cn www.opencas.org ubuntu.buct.edu.cn Android developer 最新国内镜像:http://wear.techb ...

  10. Codeforces 1304E 1-Trees and Queries (树上距离+思维)(翻译向)

    题意 给你一棵树,q个询问(x,y,a,b,k),每次问你如果在(x,y)加一条边,那么a到b能不能走k步,同一个点可以走多次 思路(翻译题解) 对于一条a到b的最短路径x,可以通过左右横跳的方法把他 ...