洛谷 P3919 【模板】可持久化线段树 1(可持久化数组)
题目描述
如题,你需要维护这样的一个长度为 NN 的数组,支持如下几种操作
- 在某个历史版本上修改某一个位置上的值
- 访问某个历史版本上的某一位置的值
此外,每进行一次操作(对于操作2,即为生成一个完全一样的版本,不作任何改动),就会生成一个新的版本。版本编号即为当前操作的编号(从1开始编号,版本0表示初始状态数组)
输入格式
输入的第一行包含两个正整数 N, MN,M, 分别表示数组的长度和操作的个数。
第二行包含NN个整数,依次为初始状态下数组各位的值(依次为 a_ia**i,1 leq i leq N1≤i≤N)。
接下来MM行每行包含3或4个整数,代表两种操作之一(ii为基于的历史版本号):
- 对于操作1,格式为v_i 1 {loc}_i {value}iv**i 1 loc**i value**i,即为在版本v_iv**i的基础上,将 a{{loc}_i}aloci 修改为 {value}_ivalue**i
- 对于操作2,格式为v_i 2 {loc}iv**i 2 loc**i,即访问版本v_iv**i中的 a{{loc}_i}aloci的值,生成一样版本的对象应为vi
输出格式
输出包含若干行,依次为每个操作2的结果。
题解:
一道主席树的板子题,没学过的请走这边:
直接放代码:
#include<cstdio>
using namespace std;
const int maxn=1e6+10;
int n,m;
int a[maxn],root[maxn];
struct persistent_segment_tree
{
int lson,rson,val;
}tree[maxn*24];
int tot,ver;
void build(int &pos,int l,int r)
{
int mid=(l+r)>>1;
if(!pos)
pos=++tot;
if(l==r)
{
tree[pos].val=a[l];
return;
}
build(tree[pos].lson,l,mid);
build(tree[pos].rson,mid+1,r);
tree[pos].val=tree[tree[pos].lson].val+tree[tree[pos].rson].val;
}
int newnode(int pos)
{
tree[++tot]=tree[pos];
return tot;
}
int update(int pos,int l,int r,int x,int k)
{
int mid=(l+r)>>1;
pos=newnode(pos);
if(l==r)
{
tree[pos].val=k;
return pos;
}
if(x<=mid)
tree[pos].lson=update(tree[pos].lson,l,mid,x,k);
else
tree[pos].rson=update(tree[pos].rson,mid+1,r,x,k);
return pos;
}
int query(int pos,int l,int r,int x)
{
int mid=(l+r)>>1;
if(l==r)
return tree[pos].val;
if(x<=mid)
return query(tree[pos].lson,l,mid,x);
else
return query(tree[pos].rson,mid+1,r,x);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(root[0],1,n);
while(m--)
{
int v,opt;
int x,k;
scanf("%d%d",&v,&opt);
if(opt==1)
{
scanf("%d%d",&x,&k);
root[++ver]=update(root[v],1,n,x,k);
}
else
{
scanf("%d",&x);
root[++ver]=root[v];
printf("%d
",query(root[v],1,n,x));
}
}
return 0;
}