可持久化线段树(主席树)

关于可持久化线段树

可持久化线段树可以将历史版本的线段树记忆下来,并支持新建版本与查询历史版本。

其中有一道经典的静态主席树的题就是求区间k大。

建树的过程其实就是先建一棵空树,再按输入顺序插入节点。需要新开节点的时候就新开,如果和之前没有什么变化的话就连到之前的树上。这样的空间复杂度据说是Θ(nlogn)

由于线段树支持区间减法,于是我们可以在查询区间的时候利用前缀和的思想,对于[L,R]的区间,我们可以让第L-1个线段树与第R个线段树相减。

代码如下:(附有较详细的注释。)

 1 //Writer : Hsz %WJMZBMR%tourist%hzwer
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cmath>
 6 #include <queue>
 7 #include <map>
 8 #include <set>
 9 #include <stack>
10 #include <vector>
11 #include <cstdlib>
12 #include <algorithm>
13 #define LL long long
14 using namespace std;
15 const int N=200005<<5;
16 int l[N],r[N],sum[N],b[N];//sum表示线段树区间内点的数量。
17 int n,m,a[N],root[N],tot;
18 int build(int L,int R) {
19     int rt=++tot;
20     if(L<R) {
21         l[rt]=build(L,(L+R)>>1);//建一个空树。l[rt]表示rt的左儿子。
22         r[rt]=build((L+R)/2+1,R);
23     }
24     return rt;
25 }
26 int update(int pre,int L,int R,int c) {//加点,把历史版本记录下来。
27     int rt=++tot;
28     l[rt]=l[pre],r[rt]=r[pre],sum[rt]=sum[pre]+1;//pre:上一棵树的根,因为插入了一个新的点,所以sum肯定比上一个多1。
29     if(L<R) {
30         if(c<=((L+R)>>1))l[rt]=update(l[pre],L,(L+R)>>1,c);//如果插入的点在这个线段树的左子树,就递归到左子树。
31         else r[rt]=update(r[pre],(L+R)/2+1,R,c);//同理。
32     }
33     return rt;//返回新建子树的根节点。
34 }
35 int query(int u,int v,int L,int R,int k) {
36     if(L==R) return L;
37     int x=sum[l[v]]-sum[l[u]];//u:区间左端点的线段树的根,v:右端点的线段树的根。
38     //如果左子树的增加的点数仍旧大于要求的k,那么就递归到左子树求。
39     if(x>=k) return query(l[u],l[v],L,(L+R)>>1,k);
40     //否则递归到右子树,减去左子树上的点个数。
41     else return query(r[u],r[v],(L+R)/2+1,R,k-x);
42 }
43 int main() {
44     cin>>n>>m;
45     for(int i=1; i<=n; i++) scanf("%d",&a[i]),b[i]=a[i];
46     sort(a+1,a+1+n);
47     int u=unique(a+1,a+1+n)-a-1;
48     root[0]=build(1,u);
49     for(int i=1; i<=n; i++) {
50         b[i]=lower_bound(a+1,a+1+u,b[i])-a;//离散化。
51         root[i]=update(root[i-1],1,u,b[i]);
52     }
53     int q,v,k;
54     for(int i=1; i<=m; i++) {
55         scanf("%d%d%d",&q,&v,&k);
56         printf("%d\n",a[query(root[q-1],root[v],1,u,k)]);
57     }
58     return 0;
59 }

猜你喜欢

转载自www.cnblogs.com/sdfzhsz/p/9027010.html