您的位置:首页 > 理论基础 > 数据结构算法

【可持久化数据结构】主席树(可持久化线段树)

2017-08-23 12:48 253 查看
在学习数据结构的路上渐行渐远。。。

学习了主席树(可持久化线段树)/(函数式线段树)。

简单的介绍一下可持久化数据结构的意思,大概就是可以保存历史版本的数据结构。

对于线段树而言,其的可持久化就是对每次操作建立不同版本的线段树,但显然,这样的时空复杂度过大,是不可接受的。

考虑只有单点修改的情况,一次操作影响的部分不过只有一条链,故可以只对这部分建立新版本,这大概就是可持久化线段树的基本思想。

对于查询,只需要使用不同版本的根进行查询即可,与线段树没有特别大的差别。

每次修改与查询的时间复杂度均为\(O(n \log_{2} n)\)。

显然,每次修改只会影响 \(O(log_{2}n)\)个线段树上的点,故每次修改只会新建立\(O(log_{2} n )\)个点,空间复杂度为\(O(n \log_{2} n)\)。

接下来就是如何新建点的问题,只需要动态开点,其中一个孩子仍为旧版本的点,新修改的链上点则为新建点即可。

例题为POJ 2104 / POJ 2761 / luogu 3834

模板如下:

#include <stdio.h>
#include <algorithm>
#define mid (l+r>>1)
#define MN 100005
#define MM (((1<<17)*17)<<1)
#define R register
inline int read(){
R int x; R char c; R bool f;
for (f=0; (c=getchar())<'0'||c>'9'; f=c=='-');
for (x=c-'0'; (c=getchar())>='0'&&c<='9'; x=(x<<3)+(x<<1)+c-'0');
return f?-x:x;
}
int ls[MM],rs[MM],v[MM],cnt,rt[MN],val[MN],rk[MN],vrk[MN],n,m;
inline bool cmp(int a,int b){return val[a]<val[b];}
inline int copy(int old){ls[++cnt]=ls[old],rs[cnt]=rs[old],v[cnt]=v[old];return cnt;}
void modify(int val,int &x,int l,int r){
x=copy(x);++v[x];if (l==r) return;
if (val<=mid) modify(val,ls[x],l,mid);
else modify(val,rs[x],mid+1,r);
}
int query(int rk,int lq,int rq,int l,int r){
if (l==r) return l;R int tmp=v[ls[rq]]-v[ls[lq]];
if (rk<=tmp) return query(rk,ls[lq],ls[rq],l,mid);
else return query(rk-tmp,rs[lq],rs[rq],mid+1,r);
}
int main(){
n=read(),m=read();
for (R int i=1; i<=n; ++i)
val[i]=read(),rk[i]=i;
std::sort(rk+1,rk+n+1,cmp);
for (R int i=1; i<=n; ++i) vrk[rk[i]]=i;
for (R int i=1; i<=n; ++i)
rt[i]=rt[i-1],modify(vrk[i],rt[i],1,n);
for (R int i=1; i<=m; ++i){
R int l=read(),r=read(),k=read();
printf("%d\n",val[rk[query(k,rt[l-1],rt[r],1,n)]]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: