博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
YSZOJ:#247. [福利]可持久化线段树 (最适合可持久化线段树入门)
阅读量:4542 次
发布时间:2019-06-08

本文共 2391 字,大约阅读时间需要 7 分钟。

题目链接:

解题心得:

  • 可持久化线段树其实就是一个线段树功能的加强版,加强在哪里呢?那就是如果一颗普通的线段树多次修改之后还能知道最开始的线段树长什么样子吗?肯定不能,如果就要问你这棵线段树在某一时刻是什么样子那能咋办。最直接的思维就是创建n棵线段树,将每一个时刻都记录下来。但是想一下时间复杂度和空间复杂度都是很大的。
  • 可持久化线段树就是解决这个问题的。仔细想一想如果只修改线段树上一个叶子结点,那么对于线段树来说有改变的节点有多少个,log n 个,也就是线段树上面的一条枝。这样就可以建立一个新的根结点将需要改变的这个枝创建出来连接到新的结点上。那没有改变的节点咋办,那就值将这个新创建的节点指向上一个时刻树上没有改变的节点就行了。 

 

////      ┏┛ ┻━━━━━┛ ┻┓//      ┃       ┃//      ┃   ━   ┃//      ┃ ┳┛   ┗┳ ┃//      ┃       ┃//      ┃   ┻   ┃//      ┃       ┃//      ┗━┓   ┏━━━┛//        ┃   ┃   神兽保佑//        ┃   ┃   代码无BUG!//        ┃   ┗━━━━━━━━━┓//        ┃           ┣┓//        ┃             ┏┛//        ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛//          ┃ ┫ ┫   ┃ ┫ ┫//          ┗━┻━┛   ┗━┻━┛#include 
using namespace std;const int maxn = 1e7+7;int lson[maxn], rson[maxn], T[maxn];int n,m,cnt = 0, sz = 0, node[maxn];void updata(int root) { node[root] = max(node[lson[root]], node[rson[root]]);}void build_tree(int &root, int l, int r){
//注意要取地质,因为是创立的新的结点 root = ++sz; if(l == r) { scanf("%d", &node[root]); return ; } int mid = (l + r) >> 1; build_tree(lson[root], l, mid); build_tree(rson[root], mid+1, r); updata(root);}void init() { scanf("%d%d",&n,&m); build_tree(T[++cnt], 1, n);}void change(int& root, int pre, int pos, int l, int r, int va){ root = ++sz;//需要改变的结点 node[root] = node[pre]; if(l == r) { node[root] = va; return ; } lson[root] = lson[pre];//新的结点的儿子直接指向前一刻树的结点 rson[root] = rson[pre]; int mid = (l + r) >> 1; if(mid >= pos) change(lson[root], lson[pre], pos, l, mid, va); else change(rson[root], rson[pre], pos, mid+1, r, va); updata(root);}int query(int root, int ql, int qr, int l, int r) { if(l == ql && r == qr) { return node[root]; } int mid = (l + r) >> 1; if(mid >= qr) return query(lson[root], ql, qr, l, mid); else if(mid < ql) return query(rson[root], ql, qr, mid+1, r); else return max(query(lson[root], ql, mid, l, mid) , query(rson[root], mid+1, qr, mid+1, r));}int main() { init(); int a,b,c,d; while(m--) { scanf("%d%d%d%d",&a,&b,&c,&d); if(a == 1) { change(T[++cnt], T[b], c, 1, n, d);//T记录第cnt课树是从哪里开始的 } else { int ans = query(T[b], c, d, 1, n); printf("%d\n",ans); } } return 0;}

 

转载于:https://www.cnblogs.com/GoldenFingers/p/9435744.html

你可能感兴趣的文章
CTF-练习平台-Misc之 中国菜刀,不再web里?
查看>>
Mac系统配置JDK环境变量
查看>>
多项式累加
查看>>
剑指offer(18)二叉搜索树的后续遍历
查看>>
微信小程序一笔记账开发进度四
查看>>
bzoj 1070 费用流
查看>>
201671010139 徐楠 第四周总结
查看>>
JAVA链表简单实现
查看>>
[转载]T-SQL(MSSQL)语句查询执行顺序
查看>>
SignalR 行实时通信最大连接数
查看>>
开发进度6
查看>>
php方法重载
查看>>
三次握手和四次挥手(二)
查看>>
MySQL中的索引
查看>>
Android开发之手势滑动(滑动手势监听)详解
查看>>
switch
查看>>
HTTP错误code大全
查看>>
PAT Advanced Level 1043
查看>>
Saltstack windows可视化操作(十四)
查看>>
MYSQL基本语句
查看>>