网址:https://www.luogu.org/problem/P3919
题意:
就是单点修改和单点查询历史版本(同时复制)。
题解:
先建一个线段树保存原版本,然后修改时就对需要修改的链建新版本,查询时就先复制树根(树根保留了树的儿子索引,所以复制了树根就相当于复制了这棵树),然后在新树中查询,结果是一样的(访问到的节点也是一样的)。所以这个是个主席树。代码不做解析,理解了洛谷P3848应该不难理解这个题。
AC代码:
#include <bits/stdc++.h> using namespace std; #define MAXN 1000005 int num[MAXN]; int cnt=-1; struct cheiftree { struct node { int l,r,val; }; node tr[MAXN*25]; int rt[MAXN]; void build(int l,int r,int &rt)//l一定是1,r一定是n { rt=++cnt; tr[rt].val=num[l]; if(l==r) return; int m=(l+r)/2; build(l,m,tr[rt].l); build(m+1,r,tr[rt].r); } void update(int l,int r,int &rt,int lst,int x,int val) { rt=++cnt; tr[rt]=tr[lst]; if(l==r) { tr[rt].val=val; return; } int m=(l+r)/2; if(x<=m) update(l,m,tr[rt].l,tr[lst].l,x,val); else update(m+1,r,tr[rt].r,tr[lst].r,x,val); } int query(int rt,int l,int r,int x) { if(l==r) return tr[rt].val; int m=(l+r)/2; if(x<=m) return query(tr[rt].l,l,m,x); else return query(tr[rt].r,m+1,r,x); } }; cheiftree tr; int main() { ios::sync_with_stdio(0); cin.tie(0); int n,m; cin>>n>>m; for(int i=1;i<=n;++i) cin>>num[i]; tr.build(1,n,tr.rt[0]); int a,b,c,d; for(int i=1;i<=m;++i) { cin>>a>>b>>c; if(b==1) { cin>>d; tr.update(1,n,tr.rt[i],tr.rt[a],c,d); } else { tr.rt[i]=tr.rt[a]; cout<<tr.query(tr.rt[i],1,n,c)<<endl; } } return 0; }