主席树
感想:
这个主席树我还是学了接近一周了,虽然思想懂得比较快,但是一直比较浮躁,所以
一直都没有静下来去看代码,但是在一周的慢慢消化中,我还是懂了主席树的思想和代码
,我也看了其他大牛的博客,都写的很好,所以我的这一篇都是比较水的
主席树是线段树的一种分支,可以解决一道题中的历史遗留问题或者第几大
例如:1,2,5,3,2,2,3,4
求区间 【3,7】中的第三小的数字,我们可以很容易的看出是3
然后这样一种类型其实就是主席树的模板题了
推荐模板题:poj2104
Poj2761
Hdu2665
算法:我的语言形容能力不好,我就尽量用图来表达吧
定义的量:
T[],sum[],R[],L[],a[],b[],d,tot,rt
T[]:第几棵树的含有的数字个数
Sum[i]:节点i含有的数字个数
L[i]:节点i的左边界
R[i]:节点i的右边界
d:去重后数组剩下的个数
Tot:最后的节点总数
1.首先我们建立一棵空树,里面每一个节点都是0
2.然后向里面加点,我们先挨着建树,没有优化,每一个节点存的是区间里的数字个数
3.用一个优化的图,这种方式不会爆内存(因为画完的话占的面积太大,所以我就举例子加入第8个点时,即树7向树8转换)
树8就是除去蓝色斜杠杠掉的节点
4.假如我们要求区间[3,7]第3小,我们就用树7去减树2再来看(l,r区间求法是:t[r]-t[l-1])
5.接着在这棵树上不断判断mid和k的关系,找到第k小
这就是这个主席树了,我们接着来看代码
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #define maxn 100005 8 using namespace std; 9 10 int sum[maxn<<5],L[maxn<<5],R[maxn<<5],t[maxn<<5]; 11 int tot,d,x,m,n,a[maxn],b[maxn]; 12 13 int build(int l,int r)//在这个问题里,这一步实际意义不大,就是建立空树 14 {// 主要是累加tot 15 int rt=(++tot); 16 int m=(l+r)>>1; 17 sum[rt]=0; 18 if(l<r) 19 { 20 build(l,m); 21 build(m+1,r); 22 } 23 return rt; 24 } 25 26 int update(int pre,int l,int r,int x) 27 { 28 int rt=(++tot); 29 L[rt]=L[pre];R[rt]=R[pre];sum[rt]=sum[pre]+1; 30 if(l<r) 31 { 32 int m=(l+r)>>1; 33 if(x<=m)L[rt]=update(L[pre],l,m,x);//需要变更的链 34 else R[rt]=update(R[pre],m+1,r,x); 35 } 36 return rt; 37 } 38 39 int query(int u,int v,int l,int r,int k) 40 { 41 if(l>=r)return l; 42 int m=(l+r)>>1; 43 int num=sum[L[v]]-sum[L[u]];//两棵树对应节点相减 44 if(num>=k){//左边已经到了第num名 45 return query(L[u],L[v],l,m,k); 46 }else return query(R[u],R[v],m+1,r,k-num); 47 48 } 49 50 int main() 51 { 52 scanf("%d%d",&n,&m); 53 for(int i=1;i<=n;i++) 54 { 55 scanf("%d",&a[i]); 56 b[i]=a[i]; 57 } 58 sort(b+1,b+n+1); 59 int d=unique(b+1,b+n+1)-(b+1);//去重后的数字个数 60 t[0]=build(1,d); 61 for(int i=1;i<=n;i++) 62 { 63 int x=lower_bound(b+1,b+d+1,a[i])-b; 64 t[i]=update(t[i-1],1,d,x); 65 } 66 for(int j=1;j<=m;j++) 67 { 68 int l,r,k; 69 scanf("%d%d%d",&l,&r,&k); 70 int y=query(t[l-1],t[r],1,d,k);//求l,r区间就是树r减去l-1 71 printf("%d\n",b[y]); 72 } 73 74 }
PS:第一次发这么长的帖子,可能会有很多瑕疵,希望诸位大佬指出
时间: 2024-10-20 09:00:46