poj 2104 K-th Number 主席树+超级详细解释

传送门:K-th Number

题目大意:给出一段数列,让你求[L,R]区间内第几大的数字!

在这里先介绍一下主席树! 
如果想了解什么是主席树,就先要知道线段树,主席树就是n棵线段树,因为线段树只能维护最大值或者最小值,要想求出第二大的数字怎么办呢?两颗线段树呗!好,那么第n大呢,就可以构造n棵线段树,这样的内存是显然会爆掉的,那么怎么办呢?因为每一次更新都是更新的是从叶子节点到根节点的一条路,路的长度大约是logn,如下图红色的为更新的时候变化的节点: 

当进行更新操作的时候,也就是新建一个线段树,但是这可线段树不会全部都建立起来,只把修改的节点建立一下就可以,如果节点不修改就可以用以前线段树的节点指向当前新建的线段树的节点,先看下图然后在解释: 
 
对于没有修改的节点就直接指向新建的线段树就可以了! 
对于每一棵线段树都是类似于下图的样子的: 
 
这棵树表示数字1出现了三次,数字2出现了1次,数字三出现了一次,数字五出现了4次,数字6出现了三次; 
用一个数组来表示就是sum[i]=j表示数字i出现了j次。 
这样在通过一般线段树的pushdown操作就变为了我们熟悉的线段树了!如下图: 

下面据一个例子[1,1,2,1,5,5,5,5,6,6,6,3]解释一下建立线段树的全部过程: 
首先是一棵空的线段树 
 
顺序的由第一个元素开始进入线段树并且开始更新: 
 
 
 
 
 
 
 
 
 
 
 

这样我们就可以知道不同状态下的线段树了,比如sum[i]当前节点对应的数字出现了几次,对于[L,R]这个区间我们就可以用sum[R]−sum[L−1]表示出如果这个区间大于k那么就从他的左子树接着找,否则从右子树中找K−(sum[R]−sum[L−1])这个多个就是第k大的数字! 
这个基于的原理举个例子就知道了我们知道区间[1,3,3,4,5]区间一共有5个元素那么第5大的就是最后一个元素了!

AC代码

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int MAXN = 100010;
const int N = MAXN*40;
int n,m,q,tot;
int T[MAXN],A[MAXN],t[MAXN];
int lson[N],rson[N],sum[N];
vector<int>V;
int getid(int x) //离散化
{
return lower_bound(V.begin(),V.end(),x)-V.begin()+1;
}
int build(int l,int r) //建立一棵空树
{
int rt = tot++;
sum[rt] = 0;
if(l!=r){
int mid=(l+r)>>1;
lson[rt] = build(l,mid);
rson[rt] = build(mid+1,r);
}
return rt;
} int update(int rt,int pos) //把数组中的元素一次加入新的线段树中
{
int nrt = tot++;
int tmp = nrt;
sum[nrt] = sum[rt]+1;
int l=1,r=m;
while(l<r) {
int mid = (l+r)>>1;
if(pos<=mid) {
lson[nrt] = tot++;
rson[nrt] = rson[rt];
nrt = lson[nrt];
rt = lson[rt];
r = mid;
}else {
rson[nrt] = tot++;
lson[nrt] = lson[rt];
nrt = rson[nrt];
rt = rson[rt];
l=mid+1;
}
sum[nrt] = sum[rt]+1;
}
return tmp;
} int query(int lrt,int rrt,int k)
{
int l=1,r=m;
while(l<r) {
int mid = (l+r)>>1;
int cnt = sum[lson[rrt]] - sum[lson[lrt]];
if(cnt>=k) {
r = mid;
lrt = lson[lrt];
rrt = lson[rrt];
} else {
l = mid+1;
k-=cnt;
lrt = rson[lrt];
rrt = rson[rrt];
}
}
return l;
}
int main()
{//freopen("in.txt","r",stdin);
scanf("%d%d",&n,&q);tot=0;
for(int i=1;i<=n;i++) {
scanf("%d",&A[i]);
V.push_back(A[i]);
}
sort(V.begin(),V.end());
V.erase(unique(V.begin(),V.end()),V.end());
m=V.size();
T[0] = build(1,m);
for(int i=1;i<=n;i++) {
T[i] = update(T[i-1],getid(A[i]));
}
while(q--) {
int x,y,k;
scanf("%d%d%d",&x,&y,&k);
printf("%d\n",V[query(T[x-1],T[y],k)-1]);
}
return 0;
}

poj 2104 K-th Number 主席树+超级详细解释的更多相关文章

  1. 【POJ 2104】 K-th Number 主席树模板题

    达神主席树讲解传送门:http://blog.csdn.net/dad3zz/article/details/50638026 2016-02-23:真的是模板题诶,主席树模板水过.今天新校网不好,没 ...

  2. 静态区间第k大(主席树)

    POJ 2104为例(主席树入门题) 思想: 可持久化线段树,也叫作函数式线段树,也叫主席树(高大上). 可持久化数据结构(Persistent data structure):利用函数式编程的思想使 ...

  3. poj2104 k-th number 主席树入门讲解

    poj2104 k-th number 主席树入门讲解 定义:主席树是一种可持久化的线段树 又叫函数式线段树   刚开始学是不是觉得很蒙逼啊 其实我也是 主席树说简单了 就是 保留你每一步操作完成之后 ...

  4. Paxos协议超级详细解释+简单实例

    转载自:  https://blog.csdn.net/cnh294141800/article/details/53768464 Paxos协议超级详细解释+简单实例   Basic-Paxos算法 ...

  5. POJ 2104 K-th Number 主席树(区间第k大)

    题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...

  6. POJ 2104:K-th Number(主席树静态区间k大)

    题目大意:对于一个序列,每次询问区间[l,r]的第k大树. 分析: 主席树模板题 program kthtree; type point=record l,r,s:longint; end; var ...

  7. POJ 2104 K-th Number ( 求取区间 K 大值 || 主席树 || 离线线段树)

    题意 : 给出一个含有 N 个数的序列,然后有 M 次问询,每次问询包含 ( L, R, K ) 要求你给出 L 到 R 这个区间的第 K 大是几 分析 : 求取区间 K 大值是个经典的问题,可以使用 ...

  8. SPOJ MKTHNUM & POJ 2104 - K-th Number - [主席树模板题]

    题目链接:http://poj.org/problem?id=2104 Description You are working for Macrohard company in data struct ...

  9. poj 2104 K-th Number(主席树,详细有用)

    poj 2104 K-th Number(主席树) 主席树就是持久化的线段树,添加的时候,每更新了一个节点的线段树都被保存下来了. 查询区间[L,R]操作的时候,只需要用第R棵树减去第L-1棵树就是区 ...

随机推荐

  1. 【windows】自动化测试持续集成(CI)环境部署

    1. 环境准备 1.1 我的环境 1.Win10 64位 2.JDK 1.8.0_121 3.Tomcat 7.0.92 4. Jenkins 2.24 5.SVN-Server 3.8.1 1.2 ...

  2. 使用Sophus练习李群SO3、SE3以及对应的李代数so3、se3

    这是高博<视觉SLAM14讲,从理论到实践>第4章的练习.加了一些注释和理解: #include <iostream>#include <cmath>using n ...

  3. 实验十二:SWING界面设计

    实验程序: import java.awt.FlowLayout;import javax.swing.*;import java.awt.Container;public class jianli ...

  4. 来说一说chrome扩展和chrome插件到底有什么区别?

    想讨论chrome扩展和chrome插件区别这个话题很久了!但是迟迟没有写.因为我自己也没有搞清楚这两者之间的区别!回想当初是因为需要寻找番羽墙插件才想到去搜索到chrome插件. 想讨论chrome ...

  5. java 十三周总结

  6. python3返回值中的none

    浏览器返回null,python3返回none,懵了. google了很多资料,不明就里,这就是没基础的后果啊呀呀呀. 上阮一峰的截图,就这么理解下凑合吧:

  7. LINUX-挂载一个文件系统

    mount /dev/hda2 /mnt/hda2 挂载一个叫做hda2的盘 - 确定目录 '/ mnt/hda2' 已经存在 umount /dev/hda2 卸载一个叫做hda2的盘 - 先从挂载 ...

  8. Django DTL模板语法中的过滤器

    template_filter_demo 过滤器相关: 一.形式:小写{{ name | lower }} 二.串联:先转义文本到HTML,再转换每行到 <p> 标签{{ my_text| ...

  9. OS X中微信双开

    1.打开系统终端: 2.下载插件,输入命令(不包括括号) git clone https://github.com/Sunnyyoung/WeChatTweak-macOS.git 并回车: 3.进入 ...

  10. vue.js编程式路由导航 --- 由浅入深

    编程式路由导航 实例中定义一个方法,这个方法绑定在标签上 然后就设置路由跳转 语法 this.$router.history.push('要跳转路由的地址') <!DOCTYPE html> ...