【Luogu】P3384主席树模板(主席树查询K小数)
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小数)的更多相关文章
- Luogu P3384 【【模板】树链剖分】
转载请注明出处,部分内容引自banananana大神的博客 ~~别说你不知道什么是树~~╮(─▽─)╭(帮你百度一下) 先来回顾两个问题:1,将树从x到y结点最短路径上所有节点的值都加上z 这也是个模 ...
- 洛谷3834 hdu2665主席树模板,动态查询区间第k小
题目链接:https://www.luogu.com.cn/problem/P3834 对于区间查询第k小的问题,在区间数量达到5e5的时候是难以用朴素数据结构实现的,这时候主席树就应运而生了,主席树 ...
- 主席树-指针实现-找第k小数
主席树,其实就是N颗线段树 只是他们公用了一部分节点(๑•̀ㅂ•́)و✧ 我大部分的代码是从一位大佬的那里看到的 我这个垃圾程序连Poj2104上的数据都过不了TLE so希望神犇能给我看看, 顺便给 ...
- 洛谷3372线段树模板题 对区间+k或者查询区间和
#include<bits/stdc++.h> using namespace std; typedef unsigned int ui; typedef long long ll; ty ...
- [Luogu 3701] 「伪模板」主席树
[Luogu 3701] 「伪模板」主席树 这是一道网络流,不是主席树,不是什么数据结构,而是网络流. 题目背景及描述都非常的暴力,以至于 Capella 在做此题的过程中不禁感到生命流逝. S 向 ...
- [luogu P3384] [模板]树链剖分
[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点 ...
- 计蒜客 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 ...
- 洛谷P3834 [模板]可持久化线段树1(主席树) [主席树]
题目传送门 可持久化线段树1(主席树) 题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个正整数构成的序列,将对于指定 ...
- 主席树的各类模板(区间第k大数【动,静】,区间不同数的个数,区间<=k的个数)
取板粗 好东西来的 1.(HDOJ2665)http://acm.hdu.edu.cn/showproblem.php?pid=2665 (POJ2104)http://poj.org/probl ...
随机推荐
- IE6常见CSS解析Bug和hack
第一:图片间隙 a:div中的图片间隙: 描述:在div中插入图片时,图片会将div下方撑大3像素 hack1:将<div>和<img>写在一行 hack2:将<img& ...
- Incredibuild导入key的方式
作者:朱金灿 来源:http://blog.csdn.net/clever101 Incredibuild5.0采用新的授权机制,在安装完服务端之后右键单击它的授权文件License .ib_lic, ...
- iOS 自适应高度,改变字体颜色
#define kMainBoundsWidth ([UIScreen mainScreen].bounds).size.width //屏幕的宽度 #define kFont [UIFont sys ...
- Idea 2017注册码
BIG3CLIK6F-eyJsaWNlbnNlSWQiOiJCSUczQ0xJSzZGIiwibGljZW5zZWVOYW1lIjoibGFuIHl1IiwiYXNzaWduZWVOYW1lIjoiI ...
- POJ 3107 Godfather (树的重心)
题意:求树的重心,若有多个,全部打印出来. 思路: 树的重心:在删除点v后,森林中的每棵树的节点数尽量均匀,若最大的那棵树的节点数最小,称v为树的重心. 这道题只是求树的所有重心,当且经当这棵树有对称 ...
- UVA10917 A walk trough the Forest (最短路,dp)
求出家到其他点的最短路径,题目的条件变成了u->v不是回头路等价于d[u]>d[v]. 然后根据这个条件建DAG图,跑dp统计方案数,dp[u] = sum(dp[v]). #includ ...
- Codeforces Round #290 (Div. 2) _B找矩形环的三种写法
http://codeforces.com/contest/510/status/B 题目大意 给一个n*m 找有没有相同字母连起来的矩形串 第一种并查集 瞎搞一下 第一次的时候把val开成字符串了 ...
- CAD交互绘制圆形云线批注(网页版)
js中实现代码说明: 动态拖放时的绘制事件: function DoDynWorldDrawFun(dX,dY,pWorldDraw,pData) { //自定义实体的GUID标识符 var sGui ...
- python小括号( )与中括号 [ ]
在python中小括号()表示的是tuple元组数据类型,元组是一种不可变序列. >>> a = (1,2,3) >>> a (1, 2, 3) >>& ...
- springboot-i18n国际化
简介 In computing, internationalization and localization are means of adapting computer software to di ...