主席树/可持久化线段树简介(洛谷P3834/P3919)
来源:互联网 发布:客管家软件好用吗 编辑:程序博客网 时间:2024/04/30 23:10
前置技能
线段树废话
主席树
介绍
我太懒了所以直接引用一下
主席树又称函数式线段树,顾名思义,也就是通过函数来实现的线段树,至于为什么叫主席树,那是因为是fotile主席创建出来的这个数据结构
算法应用及实现
主席树最经典的应用就是在线求区间第k大。
运用前缀和的思想,我们把序列的每一个前缀都建一颗线段树。每一个节点存的是这个节点对应值出现的次数,所以查询
但是如果把序列的每一个前缀都“真的”建树的话当然会MLE,而我们发现每次新加进去一个数最多只需要改变
差不多长这样(出处见右下角):
可以发现本来要新建7个点,通过共用之后只新建了3个点。这样一来,总空间就变成了
查询的时候像平衡树一样,如果k小于右子树大小查询右子树第k大,否则查询左子树的第k-sum大。
代码(洛谷P3834):
#include<cctype>#include<cstdio>#include<cstring>#include<algorithm>#define N 200005using namespace std;struct tree{ //主席树的左右儿子编号并不是x*2和x*2+1 //sum存子树大小(即这个子树的总次数) int ls,rs,sum;}t[N*20];int n,m,num,nd,rt[N*20],a[N],b[N];inline char readc(){ static char buf[100000],*l=buf,*r=buf; if (l==r) r=(l=buf)+fread(buf,1,100000,stdin); if (l==r) return EOF; return *l++;}inline int _read(){ int x=0,f=1; char ch=readc(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=readc(); } while (isdigit(ch)) x=x*10+ch-48,ch=readc(); return x*f;}void ntlz(int &x,int l,int r){//建空树 t[x=++nd].sum=0; if (l==r) return; int mid=l+r>>1; ntlz(t[x].ls,l,mid),ntlz(t[x].rs,mid+1,r);}void build(int &x,int l,int r,int fa,int p){//建树 t[x=++nd].ls=t[fa].ls,t[x].rs=t[fa].rs; t[x].sum=t[fa].sum+1; if (l==r) return; int mid=l+r>>1; if (p<=mid) build(t[x].ls,l,mid,t[fa].ls,p); else build(t[x].rs,mid+1,r,t[fa].rs,p);}int srch(int p,int q,int l,int r,int k){//查询 if (l==r) return l; int mid=l+r>>1,df=t[t[q].ls].sum-t[t[p].ls].sum;//直接相减 if (k<=df) return srch(t[p].ls,t[q].ls,l,mid,k); else return srch(t[p].rs,t[q].rs,mid+1,r,k-df);}int main(){ n=_read(),m=_read(); for (int i=1;i<=n;i++) a[i]=b[i]=_read(); sort(b+1,b+n+1),num=unique(b+1,b+n+1)-(b+1);//离散 nd=0,ntlz(rt[0],1,num); for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+num+1,a[i])-b;//a就是离散后的数组 for (int i=1;i<=n;i++) build(rt[i],1,num,rt[i-1],a[i]);//建树 while (m--){ int l=_read(),r=_read(),k=_read(); printf("%d\n",b[srch(rt[l-1],rt[r],1,num,k)]); } return 0;}
可持久化线段树
其实就是主席树
介绍
看名称就知道是什么东西了。。。
算法应用与实现
看名称就知道是干嘛的了。。。
支持查询/修改某一历史版本的信息。
同主席树一样,对于每一次修改,不用重新建树,而是改变路径上的节点信息,共用其他节点。查询的话直接查就行了。
然后就差不多了。。。
以洛谷P3919为例
#include<cctype>#include<cstdio>#include<cstring>#include<algorithm>#define N 1000005using namespace std;struct tree{ int ls,rs,x;}t[N*40];int n,m,nd,num,rt[N],a[N];inline char readc(){ static char buf[100000],*l=buf,*r=buf; if (l==r) r=(l=buf)+fread(buf,1,100000,stdin); if (l==r) return EOF; return *l++;}inline int _read(){ int x=0,f=1; char ch=readc(); while (!isdigit(ch)) { if (ch=='-') f=-1; ch=readc(); } while (isdigit(ch)) x=x*10+ch-48,ch=readc(); return x*f;}void build(int &x,int l,int r){//建树 int mid=l+r>>1; x=++nd; if (l==r) { t[x].x=a[l]; return; }; build(t[x].ls,l,mid),build(t[x].rs,mid+1,r);}void nsrt(int &x,int l,int r,int p,int w,int fa){//修改 t[x=++nd].ls=t[fa].ls,t[x].rs=t[fa].rs;//共用节点 if (l==r) { t[x].x=w; return; } int mid=l+r>>1; if (p<=mid) nsrt(t[x].ls,l,mid,p,w,t[fa].ls); else nsrt(t[x].rs,mid+1,r,p,w,t[fa].rs);}int srch(int &x,int l,int r,int p,int fa){//查询 t[x=++nd].ls=t[fa].ls,t[x].rs=t[fa].rs;//这道题要求两个操作都新增一个版本 if (l==r) return t[x].x=t[fa].x; int mid=l+r>>1; if (p<=mid) return srch(t[x].ls,l,mid,p,t[fa].ls); else return srch(t[x].rs,mid+1,r,p,t[fa].rs);}int main(){ n=_read(),m=_read(); for (int i=1;i<=n;i++) a[i]=_read(); build(rt[0],1,n); while (m--){ int v=_read(),f=_read(),p=_read(),w; if (f==1) nsrt(rt[++num],1,n,p,w=_read(),rt[v]); else printf("%d\n",srch(rt[++num],1,n,p,rt[v])); } return 0;}
阅读全文
1 0
- 主席树/可持久化线段树简介(洛谷P3834/P3919)
- 【模板主席树】洛谷p3834
- 可持久化线段树(主席树)
- 主席树(可持久化线段树)入门专题
- 主席树(可持久化线段树)学习笔记
- 主席树(可持久化线段树)
- hdu2665主席树(可持久化线段树)
- 【模板】可持久化线段树 1(主席树)
- 可持久化线段树(主席树)【数组】
- 【模板】可持久化线段树(主席树)
- 可持久化线段树(主席树)
- 【洛谷3834】 【模板】可持久化线段树 (主席树)
- spoj3267 D-query 主席树(可持久化线段树)
- 【可持久化线段树】【主席树】[HDU4417]Super Mario
- [BZOJ2653] middle - 主席树(可持久化线段树) - 二分
- 主席树(可持久化线段树)学习笔记
- 主席树/可持久化线段树总结
- 可持久化线段树——主席树
- Struts的常用标签<%@ taglib prefix="s" uri="/struts-tags"%>
- 分割回文串 II
- 最新Android平台架构
- java.lang.OutOfMemoryError: PermGen space及其解决方法
- 这是什么问题
- 主席树/可持久化线段树简介(洛谷P3834/P3919)
- C++常用库函数
- linux 中安装PDF阅读器FoxitReader
- finereport破解版有吗
- CodeForces 66 D.Petya and His Friends(构造+数论+高精度)
- Visual Builder-低代码开发平台中的AK47
- 计算机视觉之OpenCV教程 --- Mat图像类基础(二)
- 课程26 项目6
- Xgboost的简单使用2