• AC日记——[福利]可持久化线段树 cogs 2554


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

    ★★☆   输入文件: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

    【提示】

    样例解释

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

    【来源】

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

    思路:

      这个,裸模板呀;

    来,上代码:

    #include <cstdio>
    #include <iostream>
    
    #define maxn 40005
    
    using namespace std;
    
    struct TreeNodeType {
        int lc,rc,dis;
    };
    struct TreeNodeType tree[maxn*30];
    
    int if_z,n,q,root[maxn*10],cnt,tot,li,ri;
    
    char Cget;
    
    inline void in(int &now)
    {
        now=0,if_z=1,Cget=getchar();
        while(Cget>'9'||Cget<'0')
        {
            if(Cget=='-') if_z=-1;
            Cget=getchar();
        }
        while(Cget>='0'&&Cget<='9')
        {
            now=now*10+Cget-'0';
            Cget=getchar();
        }
        now*=if_z;
        return ;
    }
    
    void tree_build(int &now,int l,int r)
    {
        now=++tot;
        if(l==r)
        {
            in(tree[now].dis);
            return ;
        }
        int mid=(l+r)>>1;
        tree_build(tree[now].lc,l,mid);
        tree_build(tree[now].rc,mid+1,r);
        if(tree[tree[now].lc].dis>tree[tree[now].rc].dis) tree[now].dis=tree[tree[now].lc].dis;
        else tree[now].dis=tree[tree[now].rc].dis;
    }
    
    void tree_add(int pre,int &now,int l,int r)
    {
        now=++tot;
        if(l==r)
        {
            tree[now].dis=ri;
            return ;
        }
        int mid=(l+r)>>1;
        if(li<=mid)
        {
            tree_add(tree[pre].lc,tree[now].lc,l,mid);
            tree[now].rc=tree[pre].rc;
        }
        else
        {
            tree_add(tree[pre].rc,tree[now].rc,mid+1,r);
            tree[now].lc=tree[pre].lc;
        }
        if(tree[tree[now].lc].dis>tree[tree[now].rc].dis) tree[now].dis=tree[tree[now].lc].dis;
        else tree[now].dis=tree[tree[now].rc].dis;
    }
    
    int tree_query(int now,int l,int r)
    {
        if(l>=li&&r<=ri) return tree[now].dis;
        int mid=(l+r)>>1;
        if(li>mid) return tree_query(tree[now].rc,mid+1,r);
        else if(ri<=mid) return tree_query(tree[now].lc,l,mid);
        else return max(tree_query(tree[now].lc,l,mid),tree_query(tree[now].rc,mid+1,r));
    }
    
    int main()
    {
        freopen("longterm_segtree.in","r",stdin);
        freopen("longterm_segtree.out","w",stdout);
        in(n),in(q);
        tree_build(root[++cnt],1,n);
        int type,k;
        while(q--)
        {
            in(type);
            if(type)
            {
                in(k),in(li),in(ri);
                tree_add(root[k],root[++cnt],1,n);
            }
            else
            {
                in(k),in(li),in(ri);
                printf("%d
    ",tree_query(root[k],1,n));
            }
        }
        return 0;
    }
  • 相关阅读:
    for是个什么玩意
    面向对象 多态
    面向对象 接口
    面向对象oop
    面向对象基本
    java修饰符的作用范围
    static 关键字介绍
    JsonLayout log4j2 json格式输出日志
    多线程--Thread.join方法
    idea常用实用快捷键
  • 原文地址:https://www.cnblogs.com/IUUUUUUUskyyy/p/6575726.html
Copyright © 2020-2023  润新知