zoukankan      html  css  js  c++  java
  • 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<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
    ",query(T[k],1,n,x,y));
        }
        return 0;
    }
  • 相关阅读:
    todo---HttpClient,httpUrlConnection
    todo---callback
    todo-braintree-java
    todo--com.paypal.sdk
    todo--OkHttp基本使用
    @RequestBody 和@ResponseBody 注解详解
    常用Jar包下载
    SpringMVC 使用JSR-303进行校验 @Valid
    SpringMVC 之 表单标签
    SpringMVC 自定义类型转换器
  • 原文地址:https://www.cnblogs.com/shenben/p/6445627.html
Copyright © 2011-2022 走看看