主席树(函数式线段树)学习小结(附手绘讲解图片)

主席树是一种离线数据结构,是由很多棵线段树组成的。

第i棵线段树存的是前i个数的信息:

每一个线段存数字的出现次数(因此建树之前要离散化)。

那么n棵线段树不会MLE吗?

当然会了!

但是我们发现第i棵线段树和第i-1棵线段树是非常相似的,有许多结点完全相同,因此可以借用之前的结点,没必要新建结点。

具体建树方法建下图:

序列为 1 3 4 2

那么如果要询问i-j之间数字出现的次数怎么办呢?

因为每一棵线段树的区间都是相同的,所以要求l-r之间的数字的出现次数只要用前r位出现的次数减去前l-1位出现的次数,就是ans

但是如果有修改操作怎么办?

如果沿用上面的做法,那么修改操作是O(nlogn)的,查询是O(1)的,修改要花好长时间。。。

前缀和联想到了树状数组,那么将前缀和用树状数组维护的话修改是O(logn*logn),查询时O(logn),查询的时间虽然变长,但是修改的时间缩短许多!!

注意:

函数式线段树的数组要开大一点!!

代码:

无修改求区间第k大:

POJ2104 见这里

有修改求区间第k大:

BZOJ1901 见这里

时间: 2024-10-26 02:59:32

主席树(函数式线段树)学习小结(附手绘讲解图片)的相关文章

主席树/函数式线段树/可持久化线段树

什么是主席树 可持久化数据结构(Persistent data structure)就是利用函数式编程的思想使其支持询问历史版本.同时充分利用它们之间的共同数据来减少时间和空间消耗. 因此可持久化线段树也叫函数式线段树又叫主席树. 可持久化数据结构 在算法执行的过程中,会发现在更新一个动态集合时,需要维护其过去的版本.这样的集合称为是可持久的. 实现持久集合的一种方法时每当该集合被修改时,就将其整个的复制下来,但是这种方法会降低执行速度并占用过多的空间. 考虑一个持久集合S. 如图所示,对集合的

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

【poj2104-求区间第k大数(不修改)】主席树/可持续化线段树

第一道主席树~然而是道比较水的...因为它不用修改... 转载一个让我看懂的主席树的讲解吧:http://blog.csdn.net/regina8023/article/details/41910615 (未授权,侵权删) --------------------------------------------------------------------------------------------------------------------- 那么如果要询问i-j之间数字出现的次数

Codeforces538F A Heap of Heaps(函数式线段树)

题意:给你一个数组a[n],对于数组每次建立一个完全k叉树,对于每个节点,如果父节点的值比这个节点的值大,那么就是一个违规点,统计出1~n-1完全叉树下的违规点的各自的个数. 一个直觉的思想就是暴力,因为完全k叉树当k很大的时候,其实层数是特别小的,所以感觉暴力是可以的.注意到一个完全k叉树下v节点的儿子的公式是: k*(v-1)+2...kv+1,相应的父节点的公式是 (v+k-2)/k.儿子的编号是连续的,如果我们可以对每个节点快速的求出连续编号的节点有多少个数比它小我们就可以快速的更新答案

HDU-4866-Shooting(函数式线段树)

Problem Description In the shooting game, the player can choose to stand in the position of [1, X] to shoot, you can shoot all the nearest K targets. The value of K may be different on different shootings. There are N targets to shoot, each target oc

POJ-2104-K-th Number(函数式线段树)

Description You are working for Macrohard company in data structures department. After failing your previous task about key insertion you were asked to write a new data structure that would be able to return quickly k-th order statistics in the array

函数式线段树的个人理解

这几天一直在搞这个东西,今天总算搞懂了,函数式线段树是一种解决离线算法的数据结构,我是这样理解的,它将所有数据离散化,再对每一个节点 N 建一颗(1,N)的线段树,这是它的思路,当然如果真正的去建这么多线段树,内存肯定爆了,所以这个就是函数式线段树的高级的地方,它从分利用前缀和的思想,后一颗树和前一棵树分享了一半的节点,什么意思呢,若现在我们得到了T[N],也就是(1,N)这些节点的线段树,我们要建(1,N+1)这颗线段树T[N+1],这样我们只需要在T[N]的基础上加入a[N+1]这个节点,如

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin

【vijos】1750 建房子(线段树套线段树+前缀和)

https://vijos.org/p/1750 是不是我想复杂了.... 自己yy了个二维线段树,然后愉快的敲打. 但是wa了两法.......sad 原因是在处理第二维的更新出现了个小问题,sad. void pushup1(int x) { for1(i, 1, mm<<2) mn[x][i]=min(mn[lc][i], mn[rc][i]); } 这里注意是mm*4...我该好好想想了..这是在dbg的时候找出来的问题.sad. 我觉得很奇怪,线段树的底层节点一共就mm个,那么整棵树