主席树真是神奇的物种!

Orz一篇资料

题意:给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的更多相关文章

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

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

  2. 算法总结——主席树(poj2104)

    题目: Description You are working for Macrohard company in data structures department. After failing y ...

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

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

  4. 主席树模板(poj2104)

    主席树是可持久化线段树,可以记录线段树的历史版本. 代码中和线段树不同的是,l,r记录的是左右子树编号,因为普通的线段树版本中,左右子树自然就是o<<1和o<<1|1,但是主席 ...

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

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

  6. 【POJ2104】K-th Number(主席树)

    题意:有n个数组成的序列,要求维护数据结构支持在线的下列两种操作: 1:单点修改,将第x个数修改成y 2:区间查询,询问从第x个数到第y个之间第K大的数 n<=100000,a[i]<=1 ...

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

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

  8. POJ2104 K-th Number(主席树)

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

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

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

随机推荐

  1. Hive与HBase区别

    对于刚接触大数据的用户来说,要想区分Hive与HBase是有一定难度的.本文将尝试从其各自的定义.特点.限制.应用场景等角度来进行分析,以作抛砖引玉之用. ====Hive是什么?Apache Hiv ...

  2. 64位Windows2003下如何正确发布VesnData.Net(VDN)

    64位windows2003下发布VDN,按照正常的步骤会出现:试图加载格式不正确的程序. (异常来自 HRESULT:0x8007000B)的错误. 按照下面的步骤进行处理: 1.如果安装了64位F ...

  3. 微软职位内部推荐-Software Engineer II-Office Incubation

    微软近期Open的职位: Office China team is looking for experienced engineers to improve consumer experience i ...

  4. 使用Log Explorer查看和恢复数据

    由于一次意外操作,把QC数据库中的BUG表数据给删掉了.崩溃-上网找了下恢复方法,找到一款Log Explorer.下载安装使用后,发现这款软件的确不错,收藏ing.   本次的使用的Log Expl ...

  5. 软件工程随堂小作业—— 寻找“水王”(C++)

    一.设计思路 (1)输入发帖ID记录表 (2)从第一个ID开始,与后续的发帖ID进行比较,若相同计数器则加一,否则减一.若计数器的数值被减为零,则重新选取当前ID开始记录比较. (3)输出结果 二.源 ...

  6. java基础学习之对象转型

    对象转型(casting): 1)一个基类的引用类型变量可以指向其子类的对象 2)一个基类的引用不可以访问其子类对象新增加的成员(属性和方法) 3)可以使用引用变量instanceof类名,来判断该引 ...

  7. 【Minimum Depth of Binary Tree】cpp

    题目: Given a binary tree, find its minimum depth. The minimum depth is the number of nodes along the ...

  8. Upgrading to Java 8——第一章 Lambda表达式

    第一章 Lambda表达式 Lamada 表达式是Java SE 8中最重要的新特性,长期以来被认为是在Java中缺失的特性,它的出现使整个java 语言变得完整.至少到目前,在这节中你将学习到什么是 ...

  9. css3动画实例

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  10. 剑指offer--面试题21--相关

    题目:设计包含min函数的栈,pop(),push(),min()的时间复杂度均为O(1) 自己所写代码如下:(写‘栈’的代码还是有些不熟练!) #include <iostream> u ...