主席树

Posted onglublog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了主席树相关的知识,希望对你有一定的参考价值。

主席树是啥??

主席树其实就是可持久化线段树。。。

原来听这个名字一直觉得很厉害,但是后来知道它就是可持久化线段树之后。。。

其实根本不用看网上博客口胡就能写出来了。

可持久化数据结构

可持久化数据结构就是在原来的数据结构基础上增加访问历史版本的功能。

如果不可持久化怎考虑这个问题?

有一种直接的方法是每次操作线段树都重新开一个线段树。

这样的空间复杂度很巨大的。

 如何用有一个空间复杂度和时间复杂度更加优秀的数据结构呢?

我们发现每次修改线段树,有很多节点是没有变化的。也就是说,我们只需要对其中一部分节点进行修改就可以了。

我们另外开一个数组记录每次操作过后的根节点序号。

每次修改一个点,不直接修改那个点,而是新建一个和之前一模一样的点,之后的所有操作都在这个点上进行就可以了。

模板题

主席树

现在我们已经学会对线段树可持久化了,怎么解决这道题呢。

然后你会发现学习怎么可持久化并不难,难的在怎么运用。

在这道题中我们需要维护一个区间k大。

可以考虑把线段树的维护的范围转化为数组的值域,维护的点转化为每个元素的个数,操作的版本转化为加入第i个元素之后的元素个数。

这样子我们就可以求出每段区间里面每个元素的个数了。

然后我们就可以找出某个区间k大了。

代码

技术分享图片
 1 #include <bits/stdc++.h>
 2 #define Mid ((l+r)>>1)
 3 #define lson(x) tree[x].ls
 4 #define rson(x) tree[x].rs
 5 #define Val(x) tree[x].val
 6 using namespace std;
 7 const int N=2e6+109;
 8 int read(){
 9     char c;int num,f=1;
10     while(c=getchar(),!isdigit(c))if(c==-)f=-1;num=c-0;
11     while(c=getchar(), isdigit(c))num=num*10+c-0;
12     return f*num;
13 }
14 struct Node{
15     int ls,rs,val;
16 }tree[N*5];
17 int hver[N];
18 int rn,n,m,ct=0;
19 int a[N],ra[N],tot=0;
20 void update(int x){
21     Val(x)=Val(lson(x))+Val(rson(x));
22 }
23 int New(int l,int r,int v){
24     tree[++tot]=(Node){l,r,v};
25     return tot;
26 }
27 int Cpy(int v){
28     tree[++tot]=tree[v];
29     return tot;
30 }
31 int fd(int x){
32     int l=0,r=rn;
33     while(l<=r){
34         if(ra[Mid]==x)return Mid;
35         if(ra[Mid]<=x)l=Mid+1;
36         else r=Mid-1;
37     }
38     return -1;
39 }
40 int build(int l,int r){
41     if(l==r)return New(0,0,0);
42     //如果是一个区间,新建点 
43     return New(build(l,Mid),build(Mid+1,r),0);
44     //建左树,建右树,建当前点 
45 }
46 int add(int l,int r,int x,int rt){
47     if(l==r){
48         int now=Cpy(rt);
49         Val(now)++;
50         return now;
51     }
52     int now=Cpy(rt);
53     if(x<=Mid)lson(now)=add(l,Mid,x,lson(now));
54     else rson(now)=add(Mid+1,r,x,rson(now));
55     Val(now)++;
56     return now;
57 }
58 int query(int l,int r,int k,int a,int b){
59     if(l==r){return l;}
60     int lt=Val(lson(a))-Val(lson(b));
61     //cout<<l<<" "<<r<<" "<<Val(a)<<" "<<Val(b)<<" "<<lt<<endl;
62     //cout<<Val(lson(a))<<" "<<Val(lson(b))<<" "<<k<<endl; 
63     if(k<=lt)
64         return query(l,Mid,k,lson(a),lson(b));
65     else return query(Mid+1,r,k-lt,rson(a),rson(b));
66 }
67 /*int que_num(int l,int r,int x,int rt){
68     if(l==r)return Val(rt);
69     if(x<=Mid)return que_num(l,Mid,x,lson(rt));
70     else return que_num(Mid+1,r,x,rson(rt));
71 }*/
72 int main()
73 {
74     //freopen("data.in","r",stdin);
75     n=read();m=read();
76     for(int i=1;i<=n;i++)a[i]=ra[i]=read();
77     sort(ra+1,ra+1+n);
78     rn=unique(ra+1,ra+1+n)-ra-1;
79     hver[0]=build(1,rn);
80     //离散化以及建树 
81     for(int i=1;i<=n;i++)
82         hver[i]=add(1,rn,fd(a[i]),hver[i-1]);
83     for(int i=1;i<=m;i++){
84         int a,b,k;
85         a=read();
86         b=read();
87         k=read();
88         printf("%d
",ra[query(1,rn,k,hver[b],hver[a-1])]);
89     }
90     return 0;
91 }
View Code

 

以上是关于主席树的主要内容,如果未能解决你的问题,请参考以下文章

代码源 Div1 - 108#464. 数数(主席树,区间比k小的数的个数)HDU4417

主席树学习记录

Yangk's 静态主席树-模板

bzoj2809 [ APIO2012 ] -- 主席树

主席树

主席树 模板