zoukankan      html  css  js  c++  java
  • YSZOJ:#247. [福利]可持久化线段树 (最适合可持久化线段树入门)

    题目链接:https://syzoj.com/problem/247

    解题心得:

    • 可持久化线段树其实就是一个线段树功能的加强版,加强在哪里呢?那就是如果一颗普通的线段树多次修改之后还能知道最开始的线段树长什么样子吗?肯定不能,如果就要问你这棵线段树在某一时刻是什么样子那能咋办。最直接的思维就是创建n棵线段树,将每一个时刻都记录下来。但是想一下时间复杂度和空间复杂度都是很大的。
    • 可持久化线段树就是解决这个问题的。仔细想一想如果只修改线段树上一个叶子结点,那么对于线段树来说有改变的节点有多少个,log n 个,也就是线段树上面的一条枝。这样就可以建立一个新的根结点将需要改变的这个枝创建出来连接到新的结点上。那没有改变的节点咋办,那就值将这个新创建的节点指向上一个时刻树上没有改变的节点就行了。 
    //
    //      ┏┛ ┻━━━━━┛ ┻┓
    //      ┃       ┃
    //      ┃   ━   ┃
    //      ┃ ┳┛   ┗┳ ┃
    //      ┃       ┃
    //      ┃   ┻   ┃
    //      ┃       ┃
    //      ┗━┓   ┏━━━┛
    //        ┃   ┃   神兽保佑
    //        ┃   ┃   代码无BUG!
    //        ┃   ┗━━━━━━━━━┓
    //        ┃           ┣┓
    //        ┃             ┏┛
    //        ┗━┓ ┓ ┏━━━┳ ┓ ┏━┛
    //          ┃ ┫ ┫   ┃ ┫ ┫
    //          ┗━┻━┛   ┗━┻━┛
    #include <bits/stdc++.h>
    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
    ",ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    Ant 执行 exec cmd.exe 时路径包含空格的问题
    时区时差换算(GMT,UTC,PST,PDT)
    windows 共存多个位数不同的jdk时,eclipse的报错对应措施
    Windows下查询指定端口进程,并杀死
    关于windows的jdk
    第一阶段工作总结
    mac配置git mergetool为p4merge(2013笔记整理)
    ubuntu 14.04 安装压缩包版mysql
    关于微信公众号内嵌网页的几个meta标签
    关于js的keyCode
  • 原文地址:https://www.cnblogs.com/GoldenFingers/p/9435744.html
Copyright © 2011-2022 走看看