zoukankan      html  css  js  c++  java
  • syzoj247

    主席树

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

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

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

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

    最开始会给你一个数列,作为第1个版本。每次M操作会导致产生一个新的版本。

    修改操作可能会很多呢,如果每次都记录一个新的数列,空间和时间上都是令人无法承受的。

    所以我们需要可持久化数据结构:

    Markdown

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

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

    Markdown

    需要查询第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询问,输出正确答案

    样例

    ##input

    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
    

    #output

    4
    5
    4
    4
    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #define N 10002
    #define M 100002
    using namespace std;
    int n,q,root[N],nr,cnt,a,b,c,d;
    struct data{int l,r,ls,rs,val;}tr[M<<4];
    
    inline void read(int &x){
        char ch=getchar();x=0;
        while(!isdigit(ch))ch=getchar();
        while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    }
    
    inline void buildtr(int root,int l,int r){
        tr[root].l=l;tr[root].r=r;
        if(l==r){read(tr[root].val);return;}
        int mid=(l+r)>>1;tr[root].ls=++cnt;tr[root].rs=++cnt;
        buildtr(tr[root].ls,l,mid);buildtr(tr[root].rs,mid+1,r);
        tr[root].val=max(tr[tr[root].ls].val,tr[tr[root].rs].val);
    }
    
    inline void change(int old,int root){
        tr[root].l=tr[old].l;tr[root].r=tr[old].r;
        if(tr[old].l==tr[old].r){tr[root].val=d;return;}
        int mid=(tr[old].l+tr[old].r)>>1;
        if(c<=mid){
            tr[root].ls=++cnt;tr[root].rs=tr[old].rs;
            change(tr[old].ls,tr[root].ls);
        }
        else{
            tr[root].ls=tr[old].ls;tr[root].rs=++cnt;
            change(tr[old].rs,tr[root].rs);
        }
        tr[root].val=max(tr[tr[root].ls].val,tr[tr[root].rs].val);
    }
    
    inline int search(int now,int l,int r){
        if(tr[now].l>=l&&tr[now].r<=r)return tr[now].val;
        int res=0,mid=(tr[now].l+tr[now].r)>>1;
        if(mid>=l)res=search(tr[now].ls,l,r);
        if(mid<r)res=max(res,search(tr[now].rs,l,r));
        return res;
    }
    
    int main(){
        read(n);read(q);
        buildtr(root[++nr],1,n);
        while(q--){
            read(a);read(b);read(c);read(d);
            if(a){
                root[++nr]=++cnt;
                change(root[b],root[nr]);
            }
            else printf("%d\n",search(root[b],c,d));
        }
    }
  • 相关阅读:
    springmvc简介
    AOP的通知类型和注解配置
    word技巧之将目录放置文档的左侧
    【刷题-LeetCode】151 Reverse Words in a String
    【刷题-LeetCode】148 Sort List
    【刷题-LeetCode】150 Evaluate Reverse Polish Notation
    【刷题-LeetCode】147 Insertion Sort List
    【经验总结-博客园】博客园Silence主题模板使用
    【数学】立个flag
    python面试题
  • 原文地址:https://www.cnblogs.com/MikuKnight/p/8889063.html
Copyright © 2011-2022 走看看