题目链接

学习了一下主席树,感觉具体算法思路不大好讲。。

大概是先建个空线段树,然后类似于递推,每一个都在前一个“历史版本”的基础上建立一个新的“历史版本”,每个历史版本只需占用树高个空间(好神奇!)

查询时这道题是通过“历史版本”间作差解决

*另外提一下,在建立“历史版本”的过程中,是“新建”,而不是“更新”,是先copy过来原有的,再按个人需求改成自己的,所产生的一个新的“历史版本”

希望注释能有帮助

//吐槽一下,本人看kuangbin模板看得好费劲,一方面不习惯用lson[],rson[]数组搞线段树,另一方面他的update query函数都是用二分写的,看半天没理解。。。

以下是按个人习惯加了注释的代码

#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<cmath>
#define M 100000+5
using namespace std; const int N=1e5+;
const int INF=0x3f3f3f3f; struct node
{
int l,r; //l,r分别指向左右孩子,但由于历史的错乱,二者的值未必有规律
int size; //当前历史版本里,该节点中所包含的元素个数
//p.s. 在最后一个历史版本里,size即为总元素个数n
}tr[N*];
//主席树的初始状态为一“空架子”
//每次updata都在前一“历史版本”基础上新建h个结点,共updata n次,产生了n个历史版本,每个版本占用空间为h*sizeof(one node)
int tot; //结点建立顺序|所赋标号 int n; //共n个数
int a[N]; //读入数组
int root[N];//记录a[]中每一个数对应各“历史版本”在主席树中的根结点标号
int m; //t[]中元素个数
int t[N]; //离散数组
int pos(int x)
{
return lower_bound(t+,t++m,x)-t;
}
int q; //q个询问 int build(int l,int r)
{
int rt=tot++;
tr[rt].size=;
if(l==r) return rt;
int mid=(l+r)>>;
tr[rt].l=build(l,mid);
tr[rt].r=build(mid+,r);
return rt;
} // pre_node:最近一历史,[l,r]当前所更新到的包含x的区间
// x此次更新的“终点”
// 沿途要增加的“权值”
// p.s. 1<=l<=r<=m
int updata(int pre_node,int l,int r,int x,int v)
{
int rt=tot++; //rt为新结点的标号
tr[rt]=tr[pre_node]; //先拷贝原指向当前区间的结点
tr[rt].size+=v;
// 在函数不断向下深入过程中,更新node.size
if(l==r) return rt;
int mid=(l+r)>>;
if(x<=mid) tr[rt].l=updata(tr[pre_node].l,l,mid,x,v);
else tr[rt].r=updata(tr[pre_node].r,mid+,r,x,v);
return rt;
// 在函数逐步return过程中,更新node.l|r
} // ql,qr反应的是在a[]中的下标,对应着更新到该下标时的“历史版本”
// l,r反应的是在t[]中的下标
int query(int ql,int qr,int l,int r,int k)
{
if(l==r) return l;
int diff=tr[tr[qr].l].size-tr[tr[ql].l].size;//在更新到ql位置和更新到qr位置时两个“历史版本”下左孩子的size之差
// p.s. size的大小反应较小数的多少
int mid=(l+r)>>;
if(diff>=k) return query(tr[ql].l,tr[qr].l,l,mid,k);
else return query(tr[ql].r,tr[qr].r,mid+,r,k-diff);
}
int main()
{
while(~scanf("%d%d",&n,&q))
{
for(int i=;i<=n;i++)
scanf("%d",&a[i]),t[i]=a[i];
sort(t+,t++n);
m=unique(t+,t++n)-t-;
m++,t[m]=INF;
tot=;
root[]=build(,m);    //初始化一个空线段树
for(int i=;i<=n;i++)
{
int order=pos(a[i]);
root[i]=updata(root[i-],,m,order,);
//每次在上一次已完成的基础上新增h个结点
//从根 逐步新建结点到 a[i]在线段树上所对应的位置
//在这个逐步新建结点的过程中,要新建的结点的l,r始终满足l<=m<=r
//这些结点每一个的size都在pre_node的基础上+1
}
while(q--)
{
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
printf("%d\n",t[query(root[l-],root[r],,m,k)]);
}
}
}

poj_2104: K-th Number 【主席树】的更多相关文章

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

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

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

    poj 2104 K-th Number 主席树+超级详细解释 传送门:K-th Number 题目大意:给出一段数列,让你求[L,R]区间内第几大的数字! 在这里先介绍一下主席树! 如果想了解什么是 ...

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

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

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

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

  5. poj2104 K-th Number区间第k小值 主席树

    原来主席树就是可持久化线段树啊,刚知道,,, 作为一道裸题,还是必A的,然而一开始偷懒不写离散化跪了N多遍,后来在缪大的帮助下发现了这个问题,遂A之 ——又是这种破问题,实在不想说自己了 把n个数看成 ...

  6. POJ2104 K-th Number[主席树]【学习笔记】

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

  7. [poj2104] K-th Number (主席树)

    主席树 Description You are working for Macrohard company in data structures department. After failing y ...

  8. poj 2104 K-th Number(主席树 视频)

    K-th Number 题意: 给你一些数,让你求一个区间内,第k大的数是多少. 题解: 主席树第一题,看的qsc视频写的,戳戳戳 学到了unique函数,他的作用是:把相邻的重复的放到后面,返回值是 ...

  9. 主席树:POJ2104 K-th Number (主席树模板题)

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

  10. 【POJ2104】【HDU2665】K-th Number 主席树

    [POJ2104][HDU2665]K-th Number Description You are working for Macrohard company in data structures d ...

随机推荐

  1. 命令查看服务器SN号

    今天工作的时候,为了检查一台服务器的序列号,没必要在跑到机房里了,所以在系统下就可以看机器序列号了.如下: 1.linux取序列号: 命令执行:dmidecode |grep "Serial ...

  2. 禁止右键,禁止选中,禁止网页复制的Js代码

    document.oncontextmenu=new Function('event.returnValue=false;'); document.onselectstart=new Function ...

  3. nodejs零基础详细教程1:安装+基础概念

    第一章 建议学习时间2小时  课程共10章 学习方式:详细阅读,并手动实现相关代码 学习目标:此教程将教会大家 安装Node.搭建服务器.express.mysql.mongodb.编写后台业务逻辑. ...

  4. Win7安装Docker

    系统环境 1. windows 7 旗舰版64位 i5-2450M CPU  8G内存 2.支持“ Hardware Virtualization Technology”,并且,“virtualiza ...

  5. 多个项目MyEclipse中启动出现OutOfMemoryError: PermGen space如何解决

    在MyEclipse中启动程序运行,报错java.lang.OutOfMemoryError: PermGen space应该怎么办?这是eclipse 内存不够的原因. PermGen space的 ...

  6. Swing系列之控件一

    Swing系列之控件 JTextArea JTextArea是一个实现多行文本的控件 构造函数 JTextArea() 构造新的TextArea. JTextArea(Document doc) 构造 ...

  7. “前”方有坑,绕道而行(一)-- H5+CSS

    1. 关于  数字.英文 不换行问题: 情景:昨天测试 小程序,输入英文,没有换行,且 下方有横向滚动条: 解决:word-break: word-break:break-all; /*只对英文起作用 ...

  8. nginx 配置https 负载均衡

    1.Winodw安装openssl工具(生成SSL证书用的)免编译版本下载: http://slproweb.com/products/Win32OpenSSL.html 注意:如果openssl在使 ...

  9. mongodb入门笔记

    mongodb作为nosql中排名第一的数据库,近年来使用的人数越来越多,作为开发人员,非常有必要了解下mongodb数据库.下面就给大家介绍下mongodb数据库的基本知识,有不对的地方欢迎指正,Q ...

  10. iOS多线程开发之离不开的GCD(上篇)

    一.GCD基本概念 GCD 全称Grand Central Dispatch(大中枢队列调度),是一套低层API,提供了⼀种新的方法来进⾏并发程序编写.从基本功能上讲,GCD有点像NSOperatio ...