隐藏页面特效

COGS 2554. [福利]可持久化线段树

1|02554. [福利]可持久化线段树


★★☆   输入文件:longterm_segtree.in   输出文件:longterm_segtree.out   简单对比
时间限制:3 s   内存限制:256 MB

【题目描述】

为什么说本题是福利呢?因为这是一道非常直白的可持久化线段树的练习题,目的并不是虐人,而是指导你入门可持久化数据结构。

线段树有个非常经典的应用是处理RMQ问题,即区间最大/最小值询问问题。现在我们把这个问题可持久化一下:

Q k l r 查询数列在第k个版本时,区间[l, r]上的最大值

M k p v 把数列在第k个版本时的第p个数修改为v,并产生一个新的数列版本

最开始会给你一个数列,作为第1个版本。

每次M操作会导致产生一个新的版本。修改操作可能会很多呢,如果每次都记录一个新的数列,空间和时间上都是令人无法承受的。所以我们需要可持久化数据结构:

对于最开始的版本1,我们直接建立一颗线段树,维护区间最大值。

修改操作呢?我们发现,修改只会涉及从线段树树根到目标点上一条树链上logn个节点而已,其余的节点并不会受到影响。所以对于每次修改操作,我们可以只重建修改涉及的节点即可。就像这样:

需要查询第k个版本的最大值,那就从第k个版本的树根开始,像查询普通的线段树一样查询即可。

要计算好所需空间哦

【输入格式】

第一行两个整数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,并产生一个新的数列版本

【输出格式】

对于每个M询问,输出正确答案

【样例输入】

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

【样例输出】

4

5

4

4

【提示】

2|0样例解释


序列版本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

3|0数据范围


N <= 10000 Q <= 100000

对于每次询问操作的版本号k保证合法,

区间[l, r]一定满足1 <= l <= r <= N

【来源】

lj出题人: sxysxy。原题见: http://syzoj.com/problem/247

#include<cstdio> #include<algorithm> using namespace std; const int N=1e5+5; const int Z=N*20; int n,q,sz,cnt,a[N]; int T[N],mx[Z],ls[Z],rs[Z]; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } inline void updata(int k){ mx[k]=max(mx[ls[k]],mx[rs[k]]); } void build(int &k,int l,int r){ if(!k) k=++sz; if(l==r){mx[k]=a[l];return ;} int mid=l+r>>1; build(ls[k],l,mid); build(rs[k],mid+1,r); updata(k); } void insert(int &k,int last,int l,int r,int p,int v){ k=++sz; mx[k]=mx[last]; if(l==r){mx[k]=v;return ;} ls[k]=ls[last]; rs[k]=rs[last]; int mid=l+r>>1; if(p<=mid) insert(ls[k],ls[last],l,mid,p,v); else insert(rs[k],rs[last],mid+1,r,p,v); updata(k); } int query(int &k,int l,int r,int x,int y){ if(!k) return 0; if(l==x&&r==y) return mx[k]; int mid=l+r>>1; if(y<=mid) return query(ls[k],l,mid,x,y); else if(x>mid) return query(rs[k],mid+1,r,x,y); else return max(query(ls[k],l,mid,x,mid),query(rs[k],mid+1,r,mid+1,y)); } int main(){ freopen("longterm_segtree.in","r",stdin); freopen("longterm_segtree.out","w",stdout); n=read();q=read(); for(int i=1;i<=n;i++) a[i]=read(); build(T[++cnt],1,n); for(int i=1,opt,k,x,y;i<=q;i++){ opt=read(); k=read();x=read();y=read(); if(opt&1) insert(T[++cnt],T[k],1,n,x,y); else printf("%d\n",query(T[k],1,n,x,y)); } return 0; }

 


__EOF__

本文作者shenben
本文链接https://www.cnblogs.com/shenben/p/6445627.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   神犇(shenben)  阅读(849)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示