题目背景

这是个非常经典的主席树入门题——静态区间第K小

数据已经过加强,请使用主席树。同时请注意常数优化

题目描述

如题,给定N个正整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。

输入输出格式

输入格式:

第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。

第二行包含N个正整数,表示这个序列各项的数字。

接下来M行每行包含三个整数\(l, r, k\) , 表示查询区间\([l, r]\)内的第k小值。

输出格式:

输出包含k行,每行1个正整数,依次表示每一次查询的结果

输入输出样例

输入样例#1:

5 5

25957 6405 15770 26287 26465

2 2 1

3 4 1

4 5 1

1 2 2

4 4 1

输出样例#1:

6405

15770

26287

25957

26287

说明

数据范围:

对于20%的数据满足:\(1 \leq N, M \leq 10\)

对于50%的数据满足:\(1 \leq N, M \leq 10^3\)

对于80%的数据满足:\(1 \leq N, M \leq 10^5\)

对于100%的数据满足:\(1 \leq N, M \leq 2\cdot 10^5\)

对于数列中的所有数\(a_i\)​ ,均满足\(-{10}^9 \leq a_i \leq {10}^9\)

样例数据说明:

N=5,数列长度为5,数列从第一项开始依次为\([25957, 6405, 15770, 26287, 26465 ]\)

第一次查询为\([2, 2]\)区间内的第一小值,即为6405

第二次查询为\([3, 4]\)区间内的第一小值,即为15770

第三次查询为\([4, 5]\) 区间内的第一小值,即为26287

第四次查询为\([1, 2]\)区间内的第二小值,即为25957

第五次查询为\([4, 4]\) 区间内的第一小值,即为26287

题解

可持久化线段树模板题。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
inline int max(int a, int b){return a > b ? a : b;}
inline int min(int a, int b){return a < b ? a : b;}
inline void swap(int &x, int &y){int tmp = x;x = y;y = tmp;}
inline void read(int &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
} const int INF = 0x3f3f3f3f;
const int MAXN = 200000 + 10; struct Node
{
int ls, rs, size;
void clear(){ls = rs = size = 0;}
}node[MAXN * 40];
int n, m, stack[MAXN], top, tot, num[MAXN], cnt, fa[MAXN], pos[MAXN];
int newnode(){if(top) return stack[top --];return ++ tot;}
void delnode(int x){stack[++ top] = x;node[x].clear();}
struct Tmp{int rank,num;}tmp[MAXN];
bool cmp(Tmp a, Tmp b){return a.num < b.num;}
inline void pushup(int x){node[x].size = node[node[x].ls].size + node[node[x].rs].size;}
void build(int &o, int l = 1, int r = cnt)
{
if(!o) o = newnode();
if(l == r) return;
int mid = (l + r) >> 1;
build(node[o].ls, l, mid);
build(node[o].rs, mid + 1, r);
}
void insert(int &o, int oo, int p, int l = 1, int r = cnt)
{
if(!o) o = newnode();
node[o].size = node[oo].size + 1;
if(l == r) return;
int mid = (l + r) >> 1;
if(p <= mid) insert(node[o].ls, node[oo].ls, p, l, mid), node[o].rs = node[oo].rs;
else insert(node[o].rs, node[oo].rs, p, mid + 1, r), node[o].ls = node[oo].ls;
}
//l-1->o,r->oo, 第k小
int ask(int o, int oo, int k, int l = 1, int r = cnt)
{
if(l == r) return l;
int mid = (l + r) >> 1, a = node[node[oo].ls].size - node[node[o].ls].size;
if(a >= k) return ask(node[o].ls, node[oo].ls, k, l, mid);
else return ask(node[o].rs, node[oo].rs, k - a, mid + 1, r);
}
int main()
{
read(n), read(m);
for(int i = 1;i <= n;++ i) read(tmp[i].num), tmp[i].rank = i;
std::sort(tmp + 1, tmp + 1 + n, cmp);
tmp[0].num = -INF;
for(int i = 1;i <= n;++ i)
{
if(tmp[i].num > tmp[i - 1].num) ++ cnt, pos[cnt] = tmp[i].num;
num[tmp[i].rank] = cnt;
}
build(fa[0]);
for(int i = 1;i <= n;++ i) insert(fa[i], fa[i - 1], num[i]);
for(int i = 1;i <= m;++ i)
{
int l, r, k;read(l), read(r), read(k);
printf("%d\n", pos[ask(fa[l - 1], fa[r], k)]);
}
return 0;
}

洛谷P3834【模板】可持久化线段树 1(主席树)的更多相关文章

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

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

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

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

  3. 洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)

    题目链接 //离散化后范围1~cnt不要错 #include<cstdio> #include<cctype> #include<algorithm> //#def ...

  4. 洛谷.3835.[模板]可持久化平衡树(fhq treap)

    题目链接 对每次Merge(),Split()时产生的节点都复制一份(其实和主席树一样).时间空间复杂度都为O(qlogq).(应该更大些 因为rand()?内存真的爆炸..) 对于无修改的操作实际上 ...

  5. 洛谷P4559 [JSOI2018]列队 【70分二分 + 主席树】

    题目链接 洛谷P4559 题解 只会做\(70\)分的\(O(nlog^2n)\) 如果本来就在区间内的人是不用动的,区间右边的人往区间最右的那些空位跑,区间左边的人往区间最左的那些空位跑 找到这些空 ...

  6. ☆ [洛谷P2633] Count on a tree 「树上主席树」

    题目类型:主席树+\(LCA\) 传送门:>Here< 题意:给出一棵树.每个节点有点权.问某一条路径上排名第\(K\)小的点权是多少 解题思路 类似区间第\(K\)小,但放在了树上. 考 ...

  7. 【洛谷 P2633】 Count on a tree(主席树,树上差分)

    题目链接 思维难度0 实现难度7 建出主席树后用两点的状态减去lca和lca父亲的状态,然后在新树上跑第\(k\)小 #include <cstdio> #include <cstr ...

  8. 洛谷$P$2468 粟粟的书架 $[SDOI2010]$ 主席树

    正解:主席树 解题报告: 传送门! 题目大意是说,给定一个矩形,然后每次会给一个,这个大矩形中的一个小矩形,询问从小矩形中最少选多少个数字能满足它们之和大于等于给定数字$x$ 看起来很神的样子,完全不 ...

  9. 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)

    To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...

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

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

随机推荐

  1. Core Data could not fulfill a fault

    做项目的时候在iOS4系统遇到过这样一个crash,console显示的错误信息是"Core Data could not fulfill a fault". 字面意思是什么?&q ...

  2. hdu多校第五场1005 (hdu6628) permutation 1 排列/康托展开/暴力

    题意: 定义一个排列的差分为后一项减前一项之差构成的数列,求对于n个数的排列,差分的字典序第k小的那个,n<=20,k<=1e4. 题解: 暴力打表找一遍规律,会发现,对于n个数的排列,如 ...

  3. C++输入cin详解

    输入原理: 程序的输入都建有一个缓冲区,即输入缓冲区.一次输入过程是这样的,当一次键盘输入结束时会将输入的数据存入输入缓冲区,而cin函数直接从输入缓冲区中取数据.正因为cin函数是直接从缓冲区取数据 ...

  4. 最详尽使用指南:超快上手Jupyter Notebook

    最详尽使用指南:超快上手Jupyter Notebook - CSDN博客https://blog.csdn.net/DataCastle/article/details/78890469

  5. jmeter接口测试(基础)

    一.jmeter创建请求 1.运行jmeter:jmeter.bat 2.右键测试计划,添加一个:线程组 3.右键前面添加的线程组,添加一个:http请求 4.填写请求信息:     5.右键线程组, ...

  6. C++之程序流程_选择结构

    C/C++支持最基本的三种程序运行结构:==顺序结构.选择结构.循环结构== * 顺序结构:程序按顺序执行,不发生跳转* 选择结构:依据条件是否满足,有选择的执行相应功能* 循环结构:依据条件是否满足 ...

  7. 16-MySQL-Ubuntu-数据表的查询-分组与聚合(五)

    分组(group by)一般与聚合结合使用 (1)查询按性别分组 select gender from students group by gender; (2)查询按性别分组并统计每组的数量sele ...

  8. arm-linux-objdump 的使用

    1. 查看静态库或.o 文件的组成文件 [arm@localhost gcc]$ arm­linux­objdump ­a libhello.a 2. 查看静态库或.o 文件的络组成部分的头部分 [a ...

  9. kafka 扩展partition和replication-factor

    问题: 1. kafka的topic 是程序自己建立,默认只建立8个partitions,1个replication-factor 目的: 扩展partitions 到9个, replicatoion ...

  10. mysql清除主从复制关系

    mysql清除主从复制关系 网页转自https://www.cnblogs.com/wjoyxt/p/5343662.html mysql主从复制中,需要将主从复制关系清除,需要取消其从库角色.这可通 ...