【CJOJ2316】【模板】可持久化线段树
2017-08-20 14:37
288 查看
题面
Description
这是一道非常直白的可持久化线段树的练习题,目的并不是虐人,而是指导你入门可持久化数据结构。线段树有个非常经典的应用是处理RMQ问题,即区间最大/最小值询问问题。现在我们把这个问题可持久化一下:
Q k l r 查询数列在第k个版本时,区间[l, r]上的最大值
M k p v 把数列在第k个版本时的第p个数修改为v,并产生一个新的数列版本
最开始会给你一个数列,作为第1个版本。
每次M操作会导致产生一个新的版本。修改操作可能会很多呢,如果每次都记录一个新的数列,空间和时间上都是令人无法承受的。所以我们需要可持久化数据结构:
对于最开始的版本1,我们直接建立一颗线段树,维护区间最大值。
105ec
修改操作呢?我们发现,修改只会涉及从线段树树根到目标点上一条树链上logn个节点而已,其余的节点并不会受到影响。所以对于每次修改操作,我们可以只重建修改涉及的节点即可。就像这样:
P
需要查询第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 51 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
45
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
Source
原题见: http://syzoj.com/problem/247可持久化线段树
题解
主席树板子题自己YY了一晚上弄出来了
到时候再写主席树的东西吧。。
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define MAX 1000000 #define ll long long inline int read() { register int x=0,t=1; register char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-'){t=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();} return x*t; } struct Node//线段树节点 { int ch[2];//左儿子和右儿子 int l,r;//左节点右节点 int val;//最大值 }c[MAX]; int n,Q,a[MAX],cnt,Root[MAX]; void Build(int now,int l,int r)//构建第一版本的线段树 { ++cnt; c[now].l=l;c[now].r=r; if(l==r){c[now].val=a[l];return;} int mid=(l+r)>>1; c[now].ch[0]=cnt+1; Build(cnt+1,l,mid); c[now].ch[1]=cnt+1; Build(cnt+1,mid+1,r); c[now].val=max(c[c[now].ch[0]].val,c[c[now].ch[1]].val); } int Query(int now,int al,int ar)//查询最大值 { int l=c[now].l,r=c[now].r; if(l==al&&ar==r)return c[now].val; int lson=c[now].ch[0],rson=c[now].ch[1]; int mid=(l+r)>>1; if(ar<=mid)return Query(lson,al,ar); if(al>mid)return Query(rson,al,ar); return max(Query(lson,al,mid),Query(rson,mid+1,ar)); } void Update(int now,int k,int x) { ++cnt;int tt=cnt; c[cnt]=c[now];//直接复制要更新的节点 int l=c[now].l,r=c[now].r; if(l==r){c[cnt].val=x;return;} int mid=(l+r)>>1; if(k<=mid){c[tt].ch[0]=cnt+1;Update(c[now].ch[0],k,x);} else{c[tt].ch[1]=cnt+1;Update(c[now].ch[1],k,x);} c[tt].val=max(c[c[tt].ch[0]].val,c[c[tt].ch[1]].val); } int main() { n=read();Q=read(); for(int i=1;i<=n;++i)a[i]=read(); Build(1,1,n);Root[1]=1; int Ver=1; while(Q--) { int tt=read(),k=read(),L=read(),R=read(); if(tt==0) printf("%d\n",Query(Root[k],L,R)); else { Root[++Ver]=cnt+1;//当前新版本的根节点 Update(Root[k],L,R); } } }
相关文章推荐
- 主席树练习1——P3834 【模板】可持久化线段树 1(主席树)
- 各种树模板(splay,线段树,可持久化线段树...)
- 【模板】可持久化线段树 1(主席树)
- 【模板】可持久化线段树 1(主席树)
- 可持久化线段树模板
- P3834 【模板】可持久化线段树 1(主席树)
- 洛谷.3834.[模板]可持久化线段树(主席树 静态区间第k小)
- 【模板】可持久化线段树
- luoguP3834 【模板】可持久化线段树 1(主席树)
- 【模板】可持久化线段树(主席树)
- 【模板】可持久化线段树(主席树)
- 【洛谷3834】 【模板】可持久化线段树 (主席树)
- 可持久化数组(线段树)[模板题]
- 可持久化线段树 (模板)
- 【模板】可持久化线段树 1(主席树)
- 可持久化线段树 模板 【bzoj3932】任务查询系统
- 【模板】主席树/函数式线段树/可持久化线段树
- P3834 【模板】可持久化线段树 1(主席树)
- luogu P3834 【模板】可持久化线段树 1(主席树)
- 线段树模板--C++