可持久化数组(主席树)
模板代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> using namespace std; typedef long long LL; #define mid ((l+r)>>1) const int INF=1e9+7,MAXNODE=24e6+7,MAXN=1e6+7; int N,M,tmp[MAXN],rt[MAXN]; int val[MAXNODE],lson[MAXNODE],rson[MAXNODE],sz; void init(int &x,int l,int r){ x=++sz; if(l==r){ val[x]=tmp[l]; return; } init(lson[x],l,mid); init(rson[x],mid+1,r); } void modify(int &x,int l,int r,int p,int q,int v){ x=++sz; if(l==r){ val[x]=v; return; } lson[x]=lson[p]; rson[x]=rson[p]; val[x]=val[p]; if(q<=mid) modify(lson[x],l,mid,lson[p],q,v); else modify(rson[x],mid+1,r,rson[p],q,v); } int query(int x,int l,int r,int q){ if(l==r) return val[x]; if(q<=mid) return query(lson[x],l,mid,q); return query(rson[x],mid+1,r,q); } int main(){ scanf("%d%d",&N,&M); for(int i=1;i<=N;i++) scanf("%d",tmp+i); init(rt[0],1,N); for(int i=1;i<=M;i++){ int edit/*edition*/,oper,loc/*location*/,v/*value*/; scanf("%d%d%d",&edit,&oper,&loc); if(oper==1){ scanf("%d",&v); modify(rt[i],1,N,rt[edit],loc,v); }else{ printf("%d\n",query(rt[edit],1,N,loc)); rt[i]=rt[edit]; } } return 0; }
原题链接题面:
可持久化数组实现
1.结构:主席树
2.思想:对于每一个版本的数组建一棵线段树,因为相邻版本差异为一个数字,所以单次修改时间空间复杂度均为O(logN)
3.实现
- 先定义一些数组(主席树的常规成员):
-
const int MAXN数字个数,MAXNODE节点个数(2*N+NlogN) int N数字个数,M查询个数,tmp[MAXN]读入数值暂存数组,rt[MAXN]每个版本的线段树的根; int val[MAXNODE]线段树值,lson[MAXNODE]左儿子,rson[MAXNODE]右儿子,sz节点栈顶;
- 初始化
- 读入并建树,将版本为0的线段树为初始树根
-
scanf("%d%d",&N,&M); for(int i=1;i<=N;i++) scanf("%d",tmp+i); init(rt[0],1,N);
按照动态开点线段树常规方法建树
void init(int &x,int l,int r){ x=++sz; if(l==r){ val[x]=tmp[l]; return; } init(lson[x],l,mid); init(rson[x],mid+1,r); }
- 更新
-
void modify(int &x当前节点下标,int l,int r,int p上一个版本,int q要赋值的位置,int v值){ x=++sz; if(l==r){找到节点,赋值并退出 val[x]=v; return; } lson[x]=lson[p];复制上一个版本的节点信息 rson[x]=rson[p]; val[x]=val[p]; if(q<=mid)按照动态开点线段树遍历 modify(lson[x],l,mid,lson[p],q,v); else modify(rson[x],mid+1,r,rson[p],q,v); }
- 查询:常规线段树查询
-
int query(int x当前点下标,int l,int r,int q查询位置){ if(l==r) return val[x]; if(q<=mid) return query(lson[x],l,mid,q); return query(rson[x],mid+1,r,q); }
完整代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 #define mid ((l+r)>>1) 5 const int INF=1e9+7,MAXNODE=24e6+7,MAXN=1e6+7; 6 int N,M,tmp[MAXN],rt[MAXN]; 7 int val[MAXNODE],lson[MAXNODE],rson[MAXNODE],sz; 8 void init(int &x,int l,int r){ 9 x=++sz; 10 if(l==r){ 11 val[x]=tmp[l]; 12 return; 13 } 14 init(lson[x],l,mid); 15 init(rson[x],mid+1,r); 16 } 17 void modify(int &x,int l,int r,int p,int q,int v){ 18 x=++sz; 19 if(l==r){ 20 val[x]=v; 21 return; 22 } 23 lson[x]=lson[p]; 24 rson[x]=rson[p]; 25 val[x]=val[p]; 26 if(q<=mid) 27 modify(lson[x],l,mid,lson[p],q,v); 28 else 29 modify(rson[x],mid+1,r,rson[p],q,v); 30 } 31 int query(int x,int l,int r,int q){ 32 if(l==r) 33 return val[x]; 34 if(q<=mid) 35 return query(lson[x],l,mid,q); 36 return query(rson[x],mid+1,r,q); 37 } 38 int main(){ 39 scanf("%d%d",&N,&M); 40 for(int i=1;i<=N;i++) 41 scanf("%d",tmp+i); 42 init(rt[0],1,N); 43 for(int i=1;i<=M;i++){ 44 int edit/*edition*/,oper,loc/*location*/,v/*value*/; 45 scanf("%d%d%d",&edit,&oper,&loc); 46 if(oper==1){ 47 scanf("%d",&v); 48 modify(rt[i],1,N,rt[edit],loc,v); 49 }else{ 50 printf("%d\n",query(rt[edit],1,N,loc)); 51 rt[i]=rt[edit]; 52 } 53 } 54 return 0; 55 }