主席树,又名函数式线段树.是fotile主席创建出来的这个数据结构,所以叫主席树.
然后这里有一些最常用的主席树需要解决的问题.
主席树_ 求区间K大值
题目大意:
给一个长为n的序列,m次询问,每次询问[l, r]内第k大的数是几.n <= 100000, m <= 5000.
首先因为是多次离线求区间的K大值,而且又因为数据范围的限制,所以传统的线段树显然是不可行的.然后这里我们就需要用到主席树.
主席树,首先有几个东西需要明确.
1. 主席树内有多棵线段树, 而且利用到了类似于前缀和的思想和做法.
2. 主席树所用的储存数据的结构,是比较巧妙的,即就把前后一致的一些一样结点多棵线段树共用.
由于数据原因,所以我们一般需要先将数据离散化一波.
然后就开始讲每一棵线段树的建立.
这里引用一组数据 :
7 1
1 5 2 6 3 7 4
2 5 3
首先 我们需要建立一棵空树.
然后依次将所有的结点 按照离散化所得到的顺序将结点一个一个插进去.
在插入的时候,更新sum数组. sum数组所起的所用就是一个前缀和的作用,表示这个结点包含了几个结点.
这一步操作,类似于Splay.
直到把所有数字插入以后,情况是这样的。
那么建树的具体过程大致如上。接下来我们考虑查询。
要查询[2, 5]中第3大的数我们首先把第1棵线段树和第5棵拿出来。
然后查询就是前面说的前缀和的做法了.
第1棵线段树和第5棵线段树,之间的差值部分就是我们所需要查询的线段树部分.
查询的时候有类似于Splay 的做法. 即找到当前结点,看是否之前左儿子统计的前缀和是否大于k,如果大于k, 那么我们就继续递归下去.
直到找到一个只有一个元素的结点,即为我们所需要的答案.
然后 代码(主席树的代码比较短,需要花时间去消化):
1 #include<bits/stdc+.h> 2 const int maxn=200005; 3 int sz,T,n,m,rt[maxn],tot,lc[maxn*20],rc[maxn*20],sum[maxn*20],a[maxn],b[maxn]; 4 using namespace std; 5 void update(int &o,int l,int r,int last,int v){ 6 //o是当前结点 last是上一次更改过的结点. 7 //将每一个结点插到该插好的地方. 8 o=++tot; 9 lc[o]=lc[last]; 10 rc[o]=rc[last]; 11 //此处借用上一次的结点 12 sum[o]=sum[last]+1; 13 //因为多插入了一个结点 所以前缀和数组需要加上一个1 14 //同时sum 数组起到一个前缀和的作用 15 if(l==r) return; 16 int mid=(l+r)>>1; 17 if(v<=mid) update(lc[o],l,mid,lc[last],v); 18 else update(rc[o],mid+1,r,rc[last],v); 19 //把每一个数安装到它应该在的地方. 20 } 21 int query(int ql,int qr,int l,int r,int k){ 22 if(l==r) return l; 23 int mid=(l+r)>>1; 24 //和splay 类似的查询 25 int cnt=sum[lc[qr]]-sum[lc[ql]]; 26 if(cnt>=k) return query(lc[ql],lc[qr],l,mid,k); 27 else return query(rc[ql],rc[qr],mid+1,r,k-cnt); 28 } 29 int main() 30 { 31 scanf("%d%d",&n,&m); 32 for(int i=1;i<=n;i++) { scanf("%d",&a[i]);b[i]=a[i];} 33 sort(b+1,b+n+1); 34 sz=unique(b+1,b+n+1)-(b+1); 35 tot=0; 36 rt[0]=++tot; 37 //每一棵子树的根结点 38 //build(rt[0],1,sz); 39 for(int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+sz+1,a[i])-b; //离散化 40 for(int i=1;i<=n;i++) update(rt[i],1,sz,rt[i-1],a[i]); 41 //建造每一棵线段树 42 for(int i=1;i<=m;i++){ 43 int l,r,k;scanf("%d%d%d",&l,&r,&k); 44 printf("%d\n",b[query(rt[l-1],rt[r],1,sz,k)]); 45 } 46 return 0; 47 }
注: 以上有一些图片转自另一博客