YEAH!我也是一个AC主席树模板的人了!

其实是个半吊子

我将尽量详细的讲出我的想法。

主席树太难,我们先搞普通线段树好了

普通线段树怎么做?我的想法是查询K次最小值,每次查完把查的数改成INF,查完再改回来。。。

MDZZ

于是就有了主席树。

先不考虑主席树,我们来考虑一个奇特的线段树。

一般的线段树,数列位置是下标,而把数列维护值作为线段树中存的元素。

那我们如果反过来,把数列元素当做线段树的下标。。。???

比如说数列【4 2 3 1】

如果线段树的下标是1、2、3、4.。。。。。?

那  在数据离散之后

我们要查第K大的数是不是比较简单。。。

NIUBI!

主席树同理。主席树的每一个节点都是一颗线段树,也就是说对【1~n】的每个前缀建一棵线段树,线段树的每一个节点存前缀【1~i】中属于【L~R】的数有多少个。比如根节点是[1..n],一共i个数,sum[root] = i;根节点的左儿子是[1..(L+R)/2],若不大于(L+R)/2的数有x个,那么sum[root.left] = x)。若要查找[i..j]中第k大数时,设某结点x,那么x.sum[j] - x.sum[i - 1]就是[i..j]中在结点x内的数字总数。而对每一个前缀都建一棵树,会MLE,观察到每个[1..i]和[1..i-1]只有一条路是不一样的,那么其他的结点只要用回前一棵树的结点即可,时空复杂度为O(nlogn)。

那主席树怎么做这道题呢?

最一开始建一棵空的线段树,也就是最开始的主席树。设这第0棵线段树的根节点为rt[0],

然后一个个把原序列元素加到对应位置。

比如我们刚举的那个例子,图片如下

就像这样。观察到节点4、5、6、7对应原序列值域1~4。原序列前缀【1~0】中每个节点的值都是0.

更新时可以发现只有一条路上的节点值有改变,于是新的线段树只需要自己新建logn个节点,其他的可以从旧线段树搬来:

可以看到新的线段树使用了一部分旧线段树的节点,因为这些节点没有任何改动,新建太浪费空间时间。

这样我们得到区间[l, r]的数要查询第k大便很容易了,设左节点中存的个数为cnt,当k<=cnt时,我们直接查询左儿子中第k小的数即可,如果k>cnt,我们只要去查右儿子中第k-cnt小的数即可,这边是一道很简单的线段树了。就如查找[1, 3]的第2小数,从根节点1向下搜,发现左儿子2的个数为1,1<2,所有去右儿子3中搜第2-1级第1小的数,然后再往下搜,发现左儿子6便可以了,此时已经搜到底端,所以直接返回节点6维护的值3即可就可以了。

附上代码

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define mid ((l+r)>>1)
using namespace std;
inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} long long *que;
long long *f;
long long *rt;
long long *ls;
long long *rs;
long long *sum;
long long tot;
long long *d;
void build(long long int &o,int l,int r){
o=++tot;
sum[o]=;
if(l==r) return;
build(ls[o],l,mid);
build(rs[o],mid+,r);
} void update(long long &o,int l,int r,int last,long long p){
o=++tot;
ls[o]=ls[last];
rs[o]=rs[last];
sum[o]=sum[last]+;
if(l==r) return;
if(p<=mid) update(ls[o],l,mid,ls[last],p);
else update(rs[o],mid+,r,rs[last],p);
} long long query(int from,int to,int l,int r,long long k){
if(l==r) return l;
long long cnt=sum[ls[to]]-sum[ls[from]];
if(k<=cnt) return query(ls[from],ls[to],l,mid,k);
else return query(rs[from],rs[to],mid+,r,k-cnt);
} struct Que{
int ID,tme;
bool operator <(const Que &a)const{
return tme<a.tme;
}
}e[];
int Ans[][]; int cc=;
int ss;
int main(){
int m=read(),n=read();
que=new long long[m+];
f=new long long[m+];
rt=new long long [m*];
ls=new long long [m*];
rs=new long long [m*];
sum=new long long [m*];
d=new long long [m*];
for(int i=;i<=m;++i){
que[i]=read();
f[i]=d[i]=que[i];
}
sort(f+,f+n+);
int size=unique(f+,f+n+)-(f+);
build(rt[],,size);
for(int i=;i<=m;++i) que[i]=lower_bound(f+,f+size+,que[i])-f;
for(int i=;i<=n;++i) e[i]=(Que){i,read()};
sort(e+,e+n+);
for(int i=;i<=n;++i){
int tme=e[i].tme,ID=e[i].ID;
while(cc<=tme){
update(rt[cc],,size,rt[cc-],que[cc]);
cc++;
}
int ans=query(rt[],rt[tme],,size,++ss);
Ans[ID][]=f[ans];
Ans[ID][]=;
}
for(int i=;i<=n;++i)
if(Ans[i][])
printf("%d\n",Ans[i][]);
return ;
}

【Luogu】P3384主席树模板(主席树查询K小数)的更多相关文章

  1. Luogu P3384 【【模板】树链剖分】

    转载请注明出处,部分内容引自banananana大神的博客 ~~别说你不知道什么是树~~╮(─▽─)╭(帮你百度一下) 先来回顾两个问题:1,将树从x到y结点最短路径上所有节点的值都加上z 这也是个模 ...

  2. 洛谷3834 hdu2665主席树模板,动态查询区间第k小

    题目链接:https://www.luogu.com.cn/problem/P3834 对于区间查询第k小的问题,在区间数量达到5e5的时候是难以用朴素数据结构实现的,这时候主席树就应运而生了,主席树 ...

  3. 主席树-指针实现-找第k小数

    主席树,其实就是N颗线段树 只是他们公用了一部分节点(๑•̀ㅂ•́)و✧ 我大部分的代码是从一位大佬的那里看到的 我这个垃圾程序连Poj2104上的数据都过不了TLE so希望神犇能给我看看, 顺便给 ...

  4. 洛谷3372线段树模板题 对区间+k或者查询区间和

    #include<bits/stdc++.h> using namespace std; typedef unsigned int ui; typedef long long ll; ty ...

  5. [Luogu 3701] 「伪模板」主席树

    [Luogu 3701] 「伪模板」主席树 这是一道网络流,不是主席树,不是什么数据结构,而是网络流. 题目背景及描述都非常的暴力,以至于 Capella 在做此题的过程中不禁感到生命流逝. S 向 ...

  6. [luogu P3384] [模板]树链剖分

    [luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...

  7. 计蒜客 38229.Distance on the tree-1.树链剖分(边权)+可持久化线段树(区间小于等于k的数的个数)+离散化+离线处理 or 2.树上第k大(主席树)+二分+离散化+在线查询 (The Preliminary Contest for ICPC China Nanchang National Invitational 南昌邀请赛网络赛)

    Distance on the tree DSM(Data Structure Master) once learned about tree when he was preparing for NO ...

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

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

  9. 主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间<=k的个数)

    取板粗   好东西来的 1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665 (POJ2104)http://poj.org/probl ...

随机推荐

  1. Objective-C Composite Objects

    We can create subclass within a class cluster that defines a class that embeds within it an object. ...

  2. Linux中grep、sed、awk使用介绍

    linux文件操作命令介绍1)grepgrep 用于在文件中查找符合条件的记录grep 参数 过滤条件 文件过滤的条件中可使用正则表达式-c 显示符合的行数-i 忽略大小写-n 显示符合要求的记录,包 ...

  3. Spring IOC的Bean对象

    ---恢复内容开始--- 在Spring IOC模块中Bean是非常重要的.在这里我想给大家讲讲关于Bean对象实例化的三种注入方式: 首先,我先讲一下关于Bean对象属性值的两种注入方式:set注入 ...

  4. 剑指offer42 左旋转字符串

    自己想的一个新的写法,如果不排除length=0的情况,下面那个while是死循环 class Solution { public: string LeftRotateString(string st ...

  5. IjkPlayer播放器秒开优化以及常用Option设置

    https://blog.csdn.net/shareus/article/details/78585260 ijkplayer点播和直播视频 问题 解决及优化  https://blog.csdn. ...

  6. gdb插件使用方法

    0x00 peda peda 安装: git clone https://github.com/longld/peda.git ~/peda echo "source ~/peda/peda ...

  7. PAT (Basic Level) Practise (中文)- 1022. D进制的A+B (20)

    PAT (Basic Level) Practise (中文)-  1022. D进制的A+B (20)  http://www.patest.cn/contests/pat-b-practise/1 ...

  8. java在线聊天项目 swt可视化窗口Design 好友列表窗口

    熟练使用各种布局方式 FlowLayout 流布局 left center right等 BorderLayout 边框布局 east west sorth north center Absolute ...

  9. CS193p Lecture 9 - Animation, Autolayout

    Animation(动画) Demo Dropit续 Autolayout(自动布局) 三种添加自动布局的方法: 使用蓝色辅助虚线,右键选择建议约束(Reset to Suggested Constr ...

  10. BZOJ4513 SDOI2016 储能表 记忆化搜索(动态规划)

    题意: 题面中文,不予翻译:SDOI2016储能表 分析: 据说有大爷用一些奇怪的方法切掉了这道题%%%%% 这里用的是大众方法——动态规划. 其实这是一道类似于二进制数位dp的动态规划题,(但是实际 ...