主席树学习笔记(静态区间第k大)
题目背景
这是个非常经典的主席树入门题——静态区间第K小
数据已经过加强,请使用主席树。同时请注意常数优化
题目描述
如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值。
输入输出格式
输入格式:
第一行包含两个正整数N、M,分别表示序列的长度和查询的个数。
第二行包含N个整数,表示这个序列各项的数字。
接下来M行每行包含三个整数l, r, kl,r,k , 表示查询区间[l, r][l,r]内的第k小值。
输出格式:
输出包含k行,每行1个整数,依次表示每一次查询的结果
输入输出样例
5 5
25957 6405 15770 26287 26465
2 2 1
3 4 1
4 5 1
1 2 2
4 4 1
6405
15770
26287
25957
26287
题面非常清晰,区间第k大。首先,每次排序再还原肯定是要跪的。
这时主席树就出现了。
主席树,倒不如说是榕树(有多个根节点,但是却不是森林)。可以说是在用空间换时间。
其实这题,主席树的主体应该是一棵权值线段树。
别人都说主席树是在每个位置维护了一颗线段树,我一直以为是每一个叶节点,其实是在每一个...好吧就是叶节点。
这里可能要把历史值那一题拿出来讲讲,主席树的每一次修改只修改一条链,而不是整个换血,所以为我们的查询提供了方便。
模拟一发:
7 1
1 5 2 6 3 7 4
建树:(感谢@bestFy的数据和图!)
插完所有的之后:
(妥妥的权值线段树)
最终图只是最后一棵线段树的样子,之前的各个线段树依旧在保存着。
于是就出现了旧节点和新建的节点公用一个根节点的情况。于是就可以愉快地进行差分了(因为两个新旧节点是等价的啊)
∴两棵线段树的对应节点相减就是对应区间有的数字啦
所以对于一个区间[l, r],我们可以每次算出在[l, mid]范围内的数,如果数量>=k(k就是第k大),就往左子树走,否则就往右子树走。
于是区间第k大就完成了。
贴代码:
#include<bits/stdc++.h>
变量解释:sum:节点的总数
rt:新旧树的根节点
ls:左儿子
rs:右儿子
tot:当前节点编号
using namespace std;
const int maxn=;
int n,m,tot,sum[maxn<<],rt[maxn<<],ls[maxn<<],rs[maxn<<],a[maxn],b[maxn],len; int build(int l,int r)
{
int root=++tot;//每新建一个节点(根)
if(l==r) return root;//如果到叶节点了返回根的值,我们要记录下来
int mid=l+r>>;//二分区间
ls[root]=build(l,mid);//记录下一层的根,也就是左儿子
rs[root]=build(mid+,r);//同上
return root;//返回大根
}
int updata(int l,int r,int root,int k)
{
int newroot=++tot;//新建的根的编号
ls[newroot]=ls[root];//记录
rs[newroot]=rs[root];//建一个等价的节点,左右儿子也是旧根节点的左右儿子
sum[newroot]=sum[root]+;//每新建一条链增加一个有值的点,所以+1(权值线段树)
if(l==r) return newroot;
int mid=l+r>>;
if(k<=mid) ls[newroot]=updata(l,mid,ls[newroot],k);//
else rs[newroot]=updata(mid+,r,rs[newroot],k);
return newroot;
}
int query(int fl,int fr,int l,int r,int k)
{
int mid=l+r>>,x=sum[ls[fr]]-sum[ls[fl]];//查询区间里的东西,先遍历左儿子,不行再往右跑
if(l==r) return l;
else if(k<=x) return query(ls[fl],ls[fr],l,mid,k);//差分了
else return query(rs[fl],rs[fr],mid+,r,k-x);//差分了
}
int main()
{
int i,x,l,r,k;
scanf("%d%d",&n,&m);
for(i=;i<=n;i++)
{
scanf("%d",&a[i]);
b[i]=a[i];
}
sort(b+,b++n);
len=unique(b+,b++n)-b-;//去重,神仙操作
//printf("%d\n",len);
rt[]=build(,len);//根的“tot”(下标,第几个点)
for(i=;i<=n;i++)//要对每一个节点建树,所以n次加边
{
x=lower_bound(b+,b++len,a[i])-b;//离散化,更新相对大小,也就是把所有数的编号弄小
rt[i]=updata(,len,rt[i-],x);//新根的编号
}
for(i=;i<=m;i++)
{
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",b[query(rt[l-],rt[r],,len,k)]);//query返回的是下标,所以要这么长一串。。
}
for(int i=;i<=*n;i++)
{
//if(sum[i]==0)break;
printf("%d ",sum[i]);
}
return ;
}
(完)
主席树学习笔记(静态区间第k大)的更多相关文章
- ZOJ -2112 Dynamic Rankings 主席树 待修改的区间第K大
Dynamic Rankings 带修改的区间第K大其实就是先和静态区间第K大的操作一样.先建立一颗主席树, 然后再在树状数组的每一个节点开线段树(其实也是主席树,共用节点), 每次修改的时候都按照树 ...
- 线段树专题2-(加强版线段树-可持续化线段树)主席树 orz! ------用于解决区间第k大的问题----xdoj-1216
poj-2104(区间第K大问题) #include <iostream> #include <algorithm> #include <cstdio> #incl ...
- 可持久化线段树(主席树)——静态区间第k大
主席树基本操作:静态区间第k大 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=2e5+, ...
- HDU3473--Minimum Sum(静态区间第k大)
Minimum Sum Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tota ...
- poj2104&&poj2761 (主席树&&划分树)主席树静态区间第k大模板
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 43315 Accepted: 14296 Ca ...
- 主席树(静态区间第k大)
前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建 ...
- 静态区间第k大(归并树)
POJ 2104为例 思想: 利用归并排序的思想: 建树过程和归并排序类似,每个数列都是子树序列的合并与排序. 查询过程,如果所查询区间完全包含在当前区间中,则直接返回当前区间内小于所求数的元素个数, ...
- 主席树初步学习笔记(可持久化数组?静态区间第k大?)
我接触 OI也快1年了,然而只写了3篇博客...(而且还是从DP跳到了主席树),不知道我这个机房吊车尾什么时候才能摸到大佬们的脚后跟orz... 前言:主席树这个东西,可以说是一种非常畸形的数据结构( ...
- HDU 2665 Kth number(主席树静态区间第K大)题解
题意:问你区间第k大是谁 思路:主席树就是可持久化线段树,他是由多个历史版本的权值线段树(不是普通线段树)组成的. 具体可以看q学姐的B站视频 代码: #include<cmath> #i ...
随机推荐
- 白话系列之实现自己简单的mvc式webapi框架
前言:此文为极简mvc式的api框架,只当做入门api的解析方式,并且这里也不算是mvc框架,因为没有view层,毕竟现在大部分都属于前后端分离,当然也可以提供view层,因为只是将view当做文本返 ...
- CF401D Roman and Numbers 状压DP
CF401D 题意翻译 将n(n<=10^18)的各位数字重新排列(不允许有前导零) 求 可以构造几个mod m等于0的数字 题目描述 Roman is a young mathematicia ...
- opencv::形态学操作
形态学操作 开操作- open 闭操作- close 形态学梯度- Morphological Gradient 顶帽 – top hat 黑帽 – black hat 开操作- open 先腐蚀后膨 ...
- javascript学习总结之对象的深拷贝和浅拷贝
前言 最近在写ES6的文章的时候发现重复遇到关于javascript深拷贝和浅拷贝的问题,然后查找了一些资料,根据资料和自己的理解做了以下笔记,毕竟javascript关于深拷贝和浅拷贝的问题在一些面 ...
- Vue中axios的封装和api接口的统一管理
更新的是我csdn上的文章,需要的话可以看下,互相学习点击去我的csdn vue中axios的封装 在vue项目和后端交互获取数据时,通常使用axios库,官方文档:https://www.npmjs ...
- “Triplet network”三元组网络阅读笔记
记录<DEEP METRIC LEARNING USING TRIPLET NETWORK>阅读笔记 文章总体内容: 作者在前人提出的多个特征提取方法的基础上提出Triplet netwo ...
- .NET Core 3.0 构建和部署
Default Executables 默认可执行文件 在 dotnet build 或 dotnet publish 期间,将创建一个与你使用的 SDK 的环境和平台相匹配的可执行文件. 和其他本机 ...
- C#扩展一般用于linq
下面是dictionary的扩展 using System.Collections.Generic; namespace NetAnalysis.Common { public static clas ...
- 数据结构(四十七)归并排序(O(nlogn))
一.归并排序的定义 归并排序(Merging Sort)就是利用归并的思想实现的排序方法.它的原理是假设初始序列含有n个记录,则可以看成是n个有序的子序列,每个子序列的长度为1,然后两两归并,得到[n ...
- (记录)Ubuntu系统中运行需要导入jar包的Java程序
在学习Redis的过程中,在学到Redis客户端Jedis的时候,考虑到能不能在ubuntu下用Vim编写Java程序并且能够运行呢? 于是,首先在网上调研了一番用Vim写Java程序的可实现性. 相 ...