学习笔记第七节:主席树

正题

      主席树看上去很高级(President Tree),毕竟说的是习大大。

      但是其实理念挺low的,在百度上一查,发现,艾~这不是函数式线段树吗~

      那么说明主席树跟线段树是有着密不可分的联系的。

      说白了,我们要学习的就是,如何优化线段树的时间来换更少的空间。

前面都是废话

      我们可以用这题来引入。

      要你求静态区间第k大。

      怎么求呢?

      我们有些同学搞笑说,nm过一下加一加莫队优化emm。

      过可能是过的了,但是掌握不了主席树后面的习题怎么办??

      现在开始说。

      1.首先我们肯定想着怎么求第k大,想着想着,就发现线段树是一个不错的东西。

      2.我们用n棵线段树来维护,第i棵线段树表示的是1~i的信息,根节点维护权值为[l,r]区间的信息。

      3.信息包括(左儿子,右儿子,这个点所管理区间内的数的个数)

      4.这样就能够满足n棵线段树维护区间(求区间,前缀和相减即可),而左右儿子来满足二分查找。

      5.好像是这么吧~

       听不懂吧~

       比如说当前区间是1,5,2,3,4.

       那么你会建出n棵线段树如下

学习笔记第七节:主席树_第1张图片

      分别对应着[1],[1,5],[1,5,2],[1,5,2,3],[1,5,2,3,4];

      那么我们要处理区间的时候,就把第r棵和第l-1棵提出来,让他们相减,在找到所需位置即可。

      然后就跑,结果发现空间超限了。

      emm,又发现,时间超限了emmmm。

      其实你有没有发现,我们建出来的前缀树和它的前一个很相似。

甚至我们发现,对于前一个来说,当前的变动只有一条链(也就是log2(n))那么多而已。

所以我们就想着,假如我们要修改左儿子,能不能把右儿子连向上一个的右儿子?

而左儿子独立更新?

当然是可以的。可以看代码理解一下。 

#include
#include
#include
#include
#include
using namespace std;

int n,m;
int fact[200010];
struct node{
	int x,d;
	bool operator<(const node q)const{
		return d

其实上面的代码很冗长,只是方便读者理解罢了。

后面会写成恶心但简短的递归形式,并且会教读者动态第k大,用主席树来维护路径第k大和子树第k大(树链剖分和dfs序)。当然还有差分+主席树,该回宿舍睡觉了要不就会被阿姨抓emm,其实我的答复会更有趣无聊欢迎提问



你可能感兴趣的:(学习笔记)