POJ 2104为例(主席树入门题)

思想:

可持久化线段树,也叫作函数式线段树,也叫主席树(高大上)。

可持久化数据结构(Persistent data structure):利用函数式编程的思想使其支持询问历史版本、同时充分利用它们之间的共同数据来减少时间和空间消耗。

主席树:对原序列的每一个前缀[1..i]建立出一棵线段树维护值域上每个数的出现次数(所以要先离散化)。线段树每个节点保存的是区间中前缀对应的出现的次数

注意:

  • 这里没有使用指针,而是给每个节点编号,通过编号来将节点与左右子节点连接起来。
  • 对于前缀[1,i]和前缀[1,i+1]的线段树,如果离散化后newa[i+1]<=mid ,那么这两棵线段树的右边是完全相同的,不需要重复建立。
  • 查询过程,先查看左子树中元素的出现次数是否大于k,如果是,继续查左子树,反之查询右子树。
  • 同一区间出现次数可以直接相减得到。

代码:

#include<cstdio>
#include<algorithm>
using namespace std;//[]
const int maxn = 100010, maxm = 20 * maxn;
int tot, c;
int a[maxn], newa[maxn];
int lson[maxm], rson[maxm], t[maxm], tree[maxm];
//lson,rson记录左右节点标号,t记录每一个前缀构成的线段树的根节点标号,tree记录标号对应区间中数字出现次数
int compress(int x)//离散化
{
return lower_bound(newa+1, newa+1+c, x) - newa;
}
int build(int l, int r)
{
int root = tot++; tree[root] = 0;
int mid = (l+r)/2;
if(l == r ) return root;
lson[root] = build(l, mid);
rson[root] = build(mid + 1, r);
return root;
}
void update(int root, int newroot, int l, int r, int num)
{
tree[newroot] = tree[root] + 1;
if(l == r) return;
int mid = (l + r)/2;
if(num <= mid){
lson[newroot] = tot++;//有变动,重新建立
rson[newroot] = rson[root];//右边不变
update( lson[root], lson[newroot], l, mid, num);
}else{
rson[newroot] = tot++;//有变动,重新建立
lson[newroot] = lson[root];//左边不变
update(rson[root], rson[newroot], mid + 1, r, num);
}
}
int query(int leftroot, int rightroot, int l, int r, int k)
{
if(l == r ) return l;
int mid = (l + r)/2;
if(tree[lson[rightroot]] - tree[lson[leftroot]] >= k){
query(lson[leftroot], lson[rightroot], l, mid, k);
}else{
int temp = tree[lson[rightroot]] - tree[lson[leftroot]];
query(rson[leftroot], rson[rightroot], mid + 1, r, k - temp);
}
}
int main (void)
{
int n,m;scanf("%d%d",&n,&m);
tot = 0;
for(int i = 1; i <= n; i++) {
scanf("%d",&a[i]);
newa[i] = a[i];
}
sort(newa+1, newa+1+n);
c = unique(newa+1, newa+1+n) - newa-1;//去重
t[0] = build(1, c);//初始化
for(int i = 1; i <= n; i++){
t[i] = tot++;
update(t[i-1], t[i], 1 , c, compress(a[i]));//不断更新,建树
}
int l, r, k;
while(m--){
scanf("%d%d%d",&l,&r,&k);
printf("%d\n", newa[query(t[l-1], t[r], 1 ,c, k)]);
}
return 0;
}//1800ms

还是划分树快些。。。

真的是理解花了好久,连写再调试又花了好久。。。。。。然而只学了点毛皮。

动态区间第k大貌似要用到树状数组,过几天再来研究一下!

静态区间第k大(主席树)的更多相关文章

  1. HDU2665 求区间第K大 主席树

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2665 代码: //#include<bits/stdc++.h> #include< ...

  2. POJ-2104-K-th Number(区间第K大+主席树模板题)

    Description You are working for Macrohard company in data structures department. After failing your ...

  3. poj2104&&poj2761 (主席树&&划分树)主席树静态区间第k大模板

    K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Submissions: 43315   Accepted: 14296 Ca ...

  4. 可持久化线段树(主席树)——静态区间第k大

    主席树基本操作:静态区间第k大 #include<bits/stdc++.h> using namespace std; typedef long long LL; ,MAXN=2e5+, ...

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

    前言 如果要求一些数中的第k大值,怎么做? 可以先就这些数离散化,用线段树记录每个数字出现了多少次. ... 那么考虑用类似的方法来求静态区间第k大. 原理 假设现在要有一些数 我们可以对于每个数都建 ...

  6. 计蒜客 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 ...

  7. 静态区间第k大(归并树)

    POJ 2104为例 思想: 利用归并排序的思想: 建树过程和归并排序类似,每个数列都是子树序列的合并与排序. 查询过程,如果所查询区间完全包含在当前区间中,则直接返回当前区间内小于所求数的元素个数, ...

  8. HDU3473--Minimum Sum(静态区间第k大)

    Minimum Sum Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tota ...

  9. 主席树学习笔记(静态区间第k大)

    题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树.同时请注意常数优化 题目描述 如题,给定N个整数构成的序列,将对于指定的闭区间查询其区间内的第K小值. 输入输出 ...

  10. HDU 2665 Kth number(主席树静态区间第K大)题解

    题意:问你区间第k大是谁 思路:主席树就是可持久化线段树,他是由多个历史版本的权值线段树(不是普通线段树)组成的. 具体可以看q学姐的B站视频 代码: #include<cmath> #i ...

随机推荐

  1. ES之各种运算符,for、while、do while 、switch case循环

    运算符优先级: 在所有的运算符中,括号的优先级最高,赋值符号的优先级最低. 小括号 > 计算运算符 > 比较运算符 > 逻辑运算符 > 赋值符号———————————————— ...

  2. 怎么学好XXX

    怎么学好数据库是一个比较大题目,数据库不仅仅是写SQL那么简单,即使知道了SQL怎么写,还需要很清楚的知道这条SQL他大概扫描了多少数据,返回多少数据,是否需要创建索引.至于SQL优化是一个比较专业的 ...

  3. sql server 2008 r2 无法定位到数据库文件目录

    像这样,选择数据库文件时, 无法定位到文件夹目录,子目录下的都不显示.明明选择的这个文件夹里还有很多子文件夹,却显示不了. 解决方法: 在此文件夹上右击,属性-安全 添加红框中的用户就可以了.

  4. ECharts 3.0 初学感想及学习中遇到的瓶颈

    因为刚工作的原因,压力特别大,加上时间也不是很充足,所以最近也没怎么整理学习的东西,今天趁着手头工作完成总结一下吧, 说实话,其实ECharts 就是图表绚丽,展示数据渲染效果更加强烈,从2.0到3. ...

  5. MVC学习(一)

    http://www.cnblogs.com/QLeelulu/archive/2008/09/30/1302462.html

  6. C++ 异常处理(try catch throw)、命名空间

    一.c++工具 模板(函数模板.类模板).异常处理.命名空间等功能是c++编译器的功能,语言本身不自带,这些功能已经成为ANSI C++标准了,建议所有的编译器都带这些功能,早期的c++是没有这些功能 ...

  7. day25-2 OSI协议和socket抽象层

    目录 OSI协议 物理层 数据链路层 以太网协议 Mac地址 广播地址 网络层 获取对方Mac地址(ARP协议) 传输层 TCP协议 UDP协议 应用层 socket抽象层 OSI协议 互联网的本质就 ...

  8. PHP 数组相加 和 数组合并array_merge

    $arr1 = array("a"=>"PHP","b"=>"java","python" ...

  9. laravel-admin常见错误处理

    php artisan key:generate 新的laravle会有密钥不存在的问题,这时候我们执行这句话就可以生成秘钥了

  10. pycharm connect to github

    这位同学写得非常详细,推荐 http://www.cnblogs.com/feixuelove1009/p/5955332.html#undefined