Description
这是一道非常直白的可持久化线段树的练习题,目的并不是虐人,而是指导你入门可持久化数据结构。
线段树有个非常经典的应用是处理RMQ问题,即区间最大/最小值询问问题。现在我们把这个问题可持久化一下:
Q k l r 查询数列在第k个版本时,区间[l, r]上的最大值
M k p v 把数列在第k个版本时的第p个数修改为v,并产生一个新的数列版本
最开始会给你一个数列,作为第1个版本。
每次M操作会导致产生一个新的版本。修改操作可能会很多呢,如果每次都记录一个新的数列,空间和时间上都是令人无法承受的。所以我们需要可持久化数据结构:
对于最开始的版本1,我们直接建立一颗线段树,维护区间最大值。
修改操作呢?我们发现,修改只会涉及从线段树树根到目标点上一条树链上logn个节点而已,其余的节点并不会受到影响。所以对于每次修改操作,我们可以只重建修改涉及的节点即可。就像这样:
需要查询第k个版本的最大值,那就从第k个版本的树根开始,像查询普通的线段树一样查询即可。
Input
第一行两个整数N, Q。N是数列的长度,Q表示询问数
第二行N个整数,是这个数列
之后Q行,每行以0或者1开头,0表示查询操作Q,1表示修改操作M,格式为
0 k l r 查询数列在第k个版本时,区间[l, r]上的最大值 或者
1 k p v 把数列在第k个版本时的第p个数修改为v,并产生一个新的数列版本
Output
对于每个M询问,输出正确答案
Sample Input
4 5
1 2 3 4
0 1 1 4
1 1 3 5
0 2 1 3
0 2 4 4
0 1 2 4
Sample Output
4
5
4
4
Hint
样例解释:
序列版本1: 1 2 3 4
查询版本1的[1, 4]最大值为4
修改产生版本2: 1 2 5 4
查询版本2的[1, 3]最大值为5
查询版本1的[4, 4]最大值为4
查询版本1的[2, 4]最大值为4
N <= 10000 Q <= 100000
对于每次询问操作的版本号k保证合法,
区间[l, r]一定满足1 <= l <= r <= N
如题目中算法详解,
我的实现:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 const int N=10005,M=100005,INF=-2e8; 8 struct node{ 9 int ls,rs,val; 10 }t[M*10]; 11 int gi() 12 { 13 int str=0,f=1;char ch=getchar(); 14 while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();} 15 while(ch>='0' && ch<='9')str=(str<<1)+(str<<3)+ch-48,ch=getchar(); 16 return str*f; 17 } 18 int a[N],root[M],tot=0,num=1; 19 void build(int &rt,int l,int r) 20 { 21 rt=++tot; 22 if(l==r){ 23 t[rt].val=a[l]; 24 return ; 25 } 26 int mid=(l+r)>>1; 27 build(t[rt].ls,l,mid);build(t[rt].rs,mid+1,r); 28 t[rt].val=max(t[t[rt].ls].val,t[t[rt].rs].val); 29 } 30 int query(int rt,int l,int r,int sa,int se) 31 { 32 if(l>se || r<sa)return INF; 33 if(sa<=l && r<=se)return t[rt].val; 34 int mid=(l+r)>>1; 35 return max(query(t[rt].ls,l,mid,sa,se),query(t[rt].rs,mid+1,r,sa,se)); 36 } 37 void change(int &rt,int fa,int l,int r,int p,int to) 38 { 39 rt=++tot; 40 if(l==r){ 41 t[rt].val=to; 42 return ; 43 } 44 int mid=(l+r)>>1; 45 if(p<=mid) 46 { 47 change(t[rt].ls,t[fa].ls,l,mid,p,to); 48 t[rt].rs=t[fa].rs; 49 } 50 else 51 { 52 change(t[rt].rs,t[fa].rs,mid+1,r,p,to); 53 t[rt].ls=t[fa].ls; 54 } 55 t[rt].val=max(t[t[rt].ls].val,t[t[rt].rs].val); 56 } 57 int main() 58 { 59 int n=gi(),m=gi(); 60 for(int i=1;i<=n;i++)a[i]=gi(); 61 build(root[1],1,n); 62 int flag,k,l,r; 63 for(int i=1;i<=m;i++) 64 { 65 flag=gi();k=gi();l=gi();r=gi(); 66 if(!flag)printf("%d ",query(root[k],1,n,l,r)); 67 else change(root[++num],root[k],1,n,l,r); 68 } 69 return 0; 70 }