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 Operators and Expressions

    What is an Expression? The most basic expression consists of an operator, two operands and an assign ...

  2. VM中python2.7运行skier游戏,shell重启问题!!!!!!

    在虚拟机win7系统python2.7,在该python中运行了 父与子中的skier游戏(代码手写), 出现如下问题: ================ RESTART: C:\Python27\S ...

  3. 虚拟DOM -------- 最易理解的解释

    虚拟DOM是最先由Facebook在react里使用的, 虚拟DOM是一个特别棒的概念,我们都知道,在浏览器上进行DOM操作的时候,会特别的消耗性能而且响应.渲染特别慢,但是有了虚拟DOM就不一样了, ...

  4. [Vue warn]: Failed to mount component: template or render function not defined.解决方案

    命名视图 vue router 里有一个 模式叫做 命名视图 本来一个页面里面只能有一个路由视图 对应 一个组件,现在可以多个路由视图 对应 多个组件. 出错点 点击标签之后,<router-v ...

  5. Evaluate|GC content|Phred|BAC|heterozygous single nucleotide polymorphisms|estimate genome size|

    (Evaluate):检查reads,可使用比对软件:使用SOAPaligner重新排列:采用massively parallel next-generation sequencing technol ...

  6. 浅谈js的sort()方法

    如果调用该方法时没有使用参数,将按字母顺序对数组中的元素进行排序,说得更精确点,是按照字符编码(字符串Unicode码点)的顺序进行排序.要实现这一点,首先应把数组的元素都转换成字符串(如有必要),以 ...

  7. webuploader项目中多文件上传实例

    <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...

  8. path.join()与path.resolve()区别

    1.path.resolve([...paths]) path.resolve() 方法会把一个路径或路径片段的序列解析为一个绝对路径. 给定的路径的序列是从右往左被处理的,后面每个 path 被依次 ...

  9. Educational Codeforces Round 40千名记

    人生第二场codeforces.然而遇上了Education场这种东西 Educational Codeforces Round 40 下午先在家里睡了波觉,起来离开场还有10分钟. 但是突然想起来还 ...

  10. MySQL常用表结构查询语句

    在我们使用数据库进行查询或者建表时,经常需要查看表结构,下面以employees数据库中的departments表为例进行表结构查询: departments表:(2列9行) +---------+- ...