主席树(静态)的轻松入门

 

主席树入门

 

emmm…最近入门了主席树, 感觉其实不是很难, 主要理解了就很简单了(毕竟代码这么短)

主席树的用处:

给出一个数列,求区间 l ~ r 之间的第 k 大值

主席树的概念:

利用数列中 n 个数据建立 n 棵树, 其中第 i 棵树维护 1 ~ i 这个前缀内的数据信息
第 i 棵树中的每个节点都有其所代表的区间范围(和线段树一样), 但这些节点所代表的区间范围指的是值域范围, 
即每个节点维护 1 ~ i 之间的全部节点中在此至于范围内的数的个数

主席树的建立

(图片出自主席树详解 )

下面是一棵空树(在代码实现中可以不建树)
盗个图

之前说的主席树的概念中, 主席树是要对每个节点 i 建立一棵维护前缀信息的树.
但是对于每一个前缀数列都建一棵树所要使用的节点是 O(n logn )的.
所以… 真的如此朴素的建树的话必然会爆内存.但是我们仔细想想之后可以发现:
第 i 棵树 和 第 i-1 棵树中许多节点都是信息相同(即 在一棵树中的位置相同且维护的数值相同)的相似节点, .
那么我们可不可以考虑偷懒一点, 将上一棵树的节点直接拿过来用呢?当然是可以的, 图如下.

0

下面还有一张, 是没有重复利用节点的…森林吧 (图中相似节点编号相同).

1

将相同编号的节点合并之后是这样的:

2


主席树的模板

 1 //by Judge
 2 #include<bits/stdc++.h>
 3 #define mid (l+r>>1)
 4 using namespace std;
 5 const int M=2e5+111;
 6 inline int read(){
 7     int x=0,f=1; char c=getchar();
 8     for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
 9     for(;isdigit(c);c=getchar()) x=x*10+c-'0';
10     return x*f;
11 }
12 int n,m,q,cnt;
13 int a[M],b[M],t[M],sum[M<<5],L[M<<5],R[M<<5]; 
14 void update(int las,int &now,int l,int r,int x){  //插入节点
15     if(!now) now=++cnt; sum[now]=sum[las]+1; if(l==r) return ;
16     // l==r直接返回, 否则向下新建改变了的节点, 没改变的直接调用
17     if(x<=mid) R[now]=R[las],update(L[las],L[now],l,mid,x);
18     else L[now]=L[las],update(R[las],R[now],mid+1,r,x);
19 }
20 int query(int u,int v,int l,int r,int k){  //查询 u ~ v 区间内第 k 大的数离散后的值
21     if(l>=r) return l; int x=sum[L[v]]-sum[L[u]];
22     //这里与二分查找树类似
23     if(x>=k) return query(L[u],L[v],l,mid,k);
24     else return query(R[u],R[v],mid+1,r,k-x);
25 }
26 int main(){
27     n=read(), q=read();
28     for(int i=1;i<=n;++i)
29         b[i]=a[i]=read();
30     sort(b+1,b+1+n);
31     m=unique(b+1,b+1+n)-(b+1); //排序并去重
32     int x,y,k;
33     for(int i=1;i<=n;++i)
34         k=lower_bound(b+1,b+1+m,a[i])-b, //离散
35         update(t[i-1],t[i],1,m,k);
36     while(q--)
37         x=read(), y=read(), k=read(),
38         printf("%d\n",b[query(t[x-1],t[y],1,m,k)]); //将离散前的值输出
39     return 0;
40 }
主席树

 

最后感谢 bzt 大佬的blog

同学们bye ( ^_^ )/~~

posted @ 2018-08-02 10:07  Jμdge  阅读(628)  评论(0编辑  收藏  举报