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));
        }
    }
  • 相关阅读:
    POJ 2251 Dungeon Master
    HDU 3085 Nightmare Ⅱ
    CodeForces 1060 B Maximum Sum of Digits
    HDU 1166 敌兵布阵(树状数组)
    HDOJ 2050 折线分割平面
    HDU 5879 Cure
    HDU 1878 欧拉回路
    HDU 6225 Little Boxes
    ZOJ 2971 Give Me the Number
    HDU 2680 Choose the best route
  • 原文地址:https://www.cnblogs.com/MikuKnight/p/8889063.html
Copyright © 2011-2022 走看看