[主席树]HDOJ2665 && POJ2104 && POJ2761
主席树真是神奇的物种!
题意:给n、m
下面有n个数 (编号1到n)
有m个询问,询问的是上面的数的编号在[l,r]之间第k小的数
n、m的范围都是$10^5$
是主席树的入门题
借此来学习一下主席树
主席数利用函数式线段树来维护数列,一般用来解决区间第k大问题
空间时间的复杂度小于树套树(常数小)
划分树也可以解决区间第k大问题,但划分树不支持修改,主席树可以(用树状数组维护)
(这三道入门题都是无修改的)
我们先来YY一下这种求区间第k(大)小的题目···
最容易想到的做法就是对于每个询问,对[l, r]区间排个序,输出第k小
这样的复杂度是O($m\times nlogn$)
大家都很容易想到排序,但是对于每个询问每个区间排序的代价太大了...
再想想,让我们加入一些线段树的思想,
要求第k小,也就是与个数相关,那么我们可以 以[l,r]区间内的数的个数来建立一棵线段树
结点的值是数的个数,当我们要找第k小的数时,若左子树大于k,那么很显然第k小的数在左子树中;若左子树小于k,那么第k小的数在右子树中
建树的复杂度是O(nlogN),查询的复杂度是O(logN) (这里的N是不相同数的数量)
若我们仍对每个查询建树,那么复杂度丝毫没有降低(反而提高了),那有没有什么办法可以不要每次查询都建树呢?
(让我们联想一下前缀和) 假设我们知道[1, l-1]之间有多少个数比第k小的数小,那么我们只要减去这些数之后在[1, r]区间内第k小的数即是[l, r]区间内的第k小数
更确切的说,我们要求[l, r]区间内的第k小数 可以 用以[1, r]建立的线段树去减去以[1, l-1] 建立的线段树
这样能够减的条件是这两棵树必须是同构的。
若是不太明白, 我们来举个例子:
如有序列 1 2 5 1 3 2 2 5 1 2
我们要求 [5,10]第5小的数
(数列中不存在4、6、7、8 但根据原理就都写出来了,为方便理解,去掉了hash的步骤,实际的代码中其实只要一棵4个叶子节点的树即可)
(红色的为个数)
我们建立的[1, l-1] (也就是[1, 4])之间的树为
[1, r]也就是[1, 10]的树为
两树相减得到
我们来找第5小的数:
发现左子树为5 所以第5小的数在左边, 再往下(左4右1) 发现左边小于5了 ,所以第5小的数在右边 所以第5小的数就是3了
同样的,我们只要建立[1, i] (i是1到n之间的所有值)的所有树,每当询问[l, r]的时候,只要用[1, r]的树减去[1, l-1]的树,再找第k小就好啦
我们将这n个树看成是建立在一个大的线段树里的,也就是这个线段树的每个节点都是一个线段树( ——这就是主席树)
最初所有的树都是空树,我们并不需要建立n个空树,只要建立一个空树,也就是不必每个节点都建立一个空树
插入元素时,我们不去修改任何的结点,而是返回一个新的树( ——这就是函数式线段树)
因为每个节点都不会被修改,所以可以不断的重复用,因此插入操作的复杂度为O(logn)
总的复杂度为O((n+m)lognlogN) (听说 主席树的芭比说 加上垃圾回收, 可以减少一个log~~~ 然而这只是听说)
你以为这样就结束了吗!!
你没有发现这样空间大到爆炸吗!!!
你在每个节点都建了一个线!段!树!这不MLE才有鬼呢!!!
那怎么办呢?
$T_i$表示一棵[1, i]区间的线段树
那么$T_i$与$T_{i-1}$的区别就只有当前插入的这个元素$a_i$以及它的父亲以及他父亲的父亲以及他父亲的父亲的父亲...
也就是改变的就只有他和他上面logn个数
所以,我们并不需要建一整棵树,我们只需要 单独建立logn个结点,跟$T_{i-1}$连起来就好了
这样树的空间复杂度(NlogN)
以下是代码:
#define lson l, m
#define rson m+1, r
const int N=1e5+;
int L[N<<], R[N<<], sum[N<<];
int tot;
int a[N], T[N], Hash[N];
int build(int l, int r)
{
int rt=(++tot);
sum[rt]=;
if(l<r)
{
int m=(l+r)>>;
L[rt]=build(lson);
R[rt]=build(rson);
}
return rt;
} int update(int pre, int l, int r, int x)
{
int rt=(++tot);
L[rt]=L[pre], R[rt]=R[pre], sum[rt]=sum[pre]+;
if(l<r)
{
int m=(l+r)>>;
if(x<=m)
L[rt]=update(L[pre], lson, x);
else
R[rt]=update(R[pre], rson, x);
}
return rt;
} int query(int u, int v, int l, int r, int k)
{
if(l>=r)
return l;
int m=(l+r)>>;
int num=sum[L[v]]-sum[L[u]];
if(num>=k)
return query(L[u], L[v], lson, k);
else
return query(R[u], R[v], rson, k-num);
} int main()
{
// int t;
// scanf("%d", &t);
// while(t--)
// {
tot=;
int n, m;
scanf("%d%d", &n, &m);
for(int i=; i<=n; i++)
{
scanf("%d", &a[i]);
Hash[i]=a[i];
}
sort(Hash+, Hash+n+);
int d=unique(Hash+, Hash+n+)-Hash-;
T[]=build(, d);
for(int i=; i<=n; i++)
{
int x=lower_bound(Hash+, Hash+d+, a[i])-Hash;
T[i]=update(T[i-], , d, x);
}
while(m--)
{
int l, r, k;
scanf("%d%d%d", &l, &r, &k);
int x=query(T[l-], T[r], , d, k);
printf("%d\n", Hash[x]);
}
// }
}
POJ 2104 && HDOJ 2665 && POJ 2761
[主席树]HDOJ2665 && POJ2104 && POJ2761的更多相关文章
- 主席树:POJ2104 K-th Number (主席树模板题)
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 44952 Accepted: 14951 Ca ...
- 算法总结——主席树(poj2104)
题目: Description You are working for Macrohard company in data structures department. After failing y ...
- poj2104&&poj2761 (主席树&&划分树)主席树静态区间第k大模板
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 43315 Accepted: 14296 Ca ...
- 主席树模板(poj2104)
主席树是可持久化线段树,可以记录线段树的历史版本. 代码中和线段树不同的是,l,r记录的是左右子树编号,因为普通的线段树版本中,左右子树自然就是o<<1和o<<1|1,但是主席 ...
- 【POJ2104】【HDU2665】K-th Number 主席树
[POJ2104][HDU2665]K-th Number Description You are working for Macrohard company in data structures d ...
- 【POJ2104】K-th Number(主席树)
题意:有n个数组成的序列,要求维护数据结构支持在线的下列两种操作: 1:单点修改,将第x个数修改成y 2:区间查询,询问从第x个数到第y个之间第K大的数 n<=100000,a[i]<=1 ...
- poj2104 k-th number 主席树入门讲解
poj2104 k-th number 主席树入门讲解 定义:主席树是一种可持久化的线段树 又叫函数式线段树 刚开始学是不是觉得很蒙逼啊 其实我也是 主席树说简单了 就是 保留你每一步操作完成之后 ...
- POJ2104 K-th Number(主席树)
题目 Source http://poj.org/problem?id=2104 Description You are working for Macrohard company in data s ...
- POJ2104 K-th Number[主席树]【学习笔记】
K-th Number Time Limit: 20000MS Memory Limit: 65536K Total Submissions: 51440 Accepted: 17594 Ca ...
随机推荐
- 单行bash、shell、perl命令
主题:单行经典bash.shell.perl命令 作者:luomg 摘要: 会陆陆续的写自己工作中的常用有意思的命令,争取你能看完后就能搞定常见操作, 且尽量自少提供基本shell.perl的实现方式 ...
- responsive layout
http://cssdeck.com/labs/7wsdvxdc http://getbootstrap.com/css/ http://getbootstrap.com/2.3.2/scaffold ...
- JAVA标签的使用跳出循环
public static void main(String args[]) { int i=10,j=10; outer: while (i > 0) { inner: while (j &g ...
- "渴了么"用户场景分析
典型用户 (1)名字:王美丽 (2)年龄:21 (3)收入:勤工助学和兼职等 (4)代表的用户在市场上的比例和重要性(比例大不等同于重要性高,如付费的用户比例较少,但是影响大,所以更重要). 作为大学 ...
- nodejs笔记五--MongoDB基本环境配置及增删改查;
一.基本环境配置: 1,首先到官网(http://www.mongodb.org/downloads )下载合适的安装包,然后一步一步next安装,当然可以自己更改安装目录:安装完成之后,配置环境变量 ...
- Node.js 学习(三) NPM 使用介绍
NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从NPM服务器下载并 ...
- Reveal 破解
永久试用Reveal,只需要打开 ~/Library/Preferences/com.ittybittyapps.Reveal.plist 把IBAApplicationPersistenceData ...
- HDU 1532 Drainage Ditches 分类: Brush Mode 2014-07-31 10:38 82人阅读 评论(0) 收藏
Drainage Ditches Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- NYOJ-20 吝啬的国度 AC 分类: NYOJ 2014-01-23 12:18 200人阅读 评论(0) 收藏
#include<cstdio> #include<cstring> #include<vector> using namespace std; int pre[1 ...
- 快速、直接的XSS漏洞检测爬虫 – XSScrapy
XSScrapy是一个快速.直接的XSS漏洞检测爬虫,你只需要一个URL,它便可以帮助你发现XSS跨站脚本漏洞. XSScrapy的XSS漏洞攻击测试向量将会覆盖 Http头中的Referer字段 U ...