欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

P3834 【模板】可持久化线段树 1(主席树)

发布时间:2024/10/12 编程问答 53 豆豆
生活随笔 收集整理的这篇文章主要介绍了 P3834 【模板】可持久化线段树 1(主席树) 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

传送门

如标题,主席树模板

稍微介绍一下主席树..

主席树是很多个线段树的结合体

利用了单点修改不会更新太多节点的结论(反正这一题是这样..),后一个线段树借用前面线段树的节点,而对于更新的节点才开一个新的节点存储数据,大大的节省了时间和空间

(除第一颗树外其他树的构建只要log(n)的时间和空间)

具体还是看代码吧

#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; const int N=200010; int n,m,a[N],b[N],cnt; int rt[N<<5],L[N<<5],R[N<<5],sz[N<<5]; //rt为根节点编号 //L[i]为节点i的左子树编号,R[i]是节点i的右子树编号 //sz[i]是以节点i为根的子树的大小 inline int build(int l,int r) //建立第一颗线段树,不解释 {int root=++cnt;if(l==r) return root;int mid=l+r>>1;L[root]=build(l,mid);R[root]=build(mid+1,r); } inline int add(int l,int r,int k,int pre)//添加新节点 {int root=++cnt; sz[root]=sz[pre]+1;//因为每次添加的线段树都比前一个线段树多一个节点//所以sz也要比上一个线段树多1if(l==r) return root; //如果到边界就返回int mid=l+r>>1;L[root]=L[pre]; R[root]=R[pre]; //借用前面线段树的节点if(k<=mid) L[root]=add(l,mid,k,L[pre]);//如果更新的值的位置在左子树就添加新节点到左边,并覆盖L[root]else R[root]=add(mid+1,r,k,R[pre]);//反之就添加新节点到右边,同样要覆盖return root;//返回新节点的编号 } inline int query(int l,int r,int hea,int las,int k)//查询区间第k名 {if(l==r) return l; //如果到边界就返回节点编号//找排名的基本操作int mid=l+r>>1,x=sz[L[las]]-sz[L[hea]]; if(x>=k) return query(l,mid,L[hea],L[las],k);return query(mid+1,r,R[hea],R[las],k-x); } int main() {cin>>n>>m;for(int i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=a[i];sort(b+1,b+n+1);//排序int len=unique(b+1,b+n+1)-b-1;//去重rt[0]=build(1,len);//建树for(int i=1;i<=n;i++){int t=lower_bound(b+1,b+len+1,a[i])-b;//在b中找<=a[i]的最大位置rt[i]=add(1,len,t,rt[i-1]);//加点 }int x,y,z;while(m--){scanf("%d%d%d",&x,&y,&z);printf("%d\n",b[query(1,len,rt[x-1],rt[y],z)]);}return 0; }

 

转载于:https://www.cnblogs.com/LLTYYC/p/9536454.html

总结

以上是生活随笔为你收集整理的P3834 【模板】可持久化线段树 1(主席树)的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。