zoukankan      html  css  js  c++  java
  • 学习笔记——可持久化线段树

    例题

    luogu 3919

    特点:在普通线段树支持查询当前状态基础上,支持查询过去的所有版本

    一、( ext{基础思路})

    暴力保存过去版本,每一次修改都会造成(nlogn)的时空复杂度,总复杂度(O)((mnlogn)),直接上天

    注意到每一次单点修改只会导致对应的叶子节点以及它的所有祖先存储的值改变,我们可以考虑只存储这一条链,将这条链连到原来的树上,单次时空复杂度(logn)

    每次修改一定会影响根节点,所以每次修改都会换一个新的根,并且可以看出,由每个根向下都可以遍历出一颗形状完全相同的线段树,所以每个根直接对应自己的版本,访问一个版本直接从这个根向下就行了

    注:可持久化线段树要存左右儿子,不能直接2或者2+1表示左右儿子

    二、( ext{流程})

    线段树其他所有操作不变(除了根节点变了),只影响查询操作

    查询向下递归的过程中,每到一个点,申请一个新节点(t),其信息和当前点完全相同,然后继续向下,如果向左递归就将左儿子修改为左边即将有的新节点编号,右儿子不变,如果右递归则相反。回溯时同样也需要(pushup)

    (luogu) 3919

    (Code)

    这道题只有单点查询,不需要维护中间节点,只需要维护叶子节点的值就行了,实际上进一步削弱了难度(甚至不需要这个算法(雾))

    #include<bits/stdc++.h>
    #define N 6000005
    using namespace std;
    int n,m;
    int a[N];
    int root[N],sum[N*4],ls[N*4],rs[N*4],ndsum;
    
    
    template <class T>
    void read(T &x)
    {
        char c;int sign=1;
        while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
        while((c=getchar())>='0'&&c<='9') x=(x<<1)+(x<<3)+c-48; x*=sign;
    }
    
    void build(int &rt,int l,int r)//初始建树
    {
        if(!rt) rt=++ndsum;
        if(l==r)
        {
            sum[rt]=a[l];
            return;
        }
        int mid=(l+r)>>1;
        build(ls[rt],l,mid);
        build(rs[rt],mid+1,r);
    }
    void copynode(int x,int y)//复制
    {
        ls[x]=ls[y];
        rs[x]=rs[y];
        sum[x]=sum[y];
    }
    int modify(int rt,int l,int r,int x,int v)//一次修改
    {
        int t=++ndsum;
        copynode(t,rt);//复制这个节点
        if(l==x&&r==x)
        {
            sum[t]=v;
            return t;
        }
        int mid=(l+r)>>1;
        if(mid>=x) ls[t]=modify(ls[rt],l,mid,x,v);//左边
        else rs[t]=modify(rs[rt],mid+1,r,x,v);//右边
        return t;//返回这个点的编号
    }
    int query(int rt,int l,int r,int x)
    {
        if(l==x&&r==x) return sum[rt];
        int mid=(l+r)>>1;
        if(mid>=x) return query(ls[rt],l,mid,x);
        else return query(rs[rt],mid+1,r,x);
    }
    
    int main()
    {
        read(n);read(m);
        for(int i=1;i<=n;++i) read(a[i]);
        build(root[0],1,n);
        for(int i=1;i<=m;++i)
        {
            int v,k,x,y;
            read(v),read(k);read(x);
            if(k==1)
            {
                read(y);
                root[i]=modify(root[v],1,n,x,y);//从root[v]开始的
            }
            else
            {
                root[i]=root[v];//询问也算一次操作,没有修改直接就copy一遍v就行
                printf("%d
    ",query(root[v],1,n,x));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    解决xcode5升级后,Undefined symbols for architecture arm64:问题
    第8章 Foundation Kit介绍
    app 之间发送文件 ios
    iphone怎么检测屏幕是否被点亮 (用UIApplication的Delegate)
    CRM下载对象一直处于Wait状态的原因
    错误消息Customer classification does not exist when downloading
    How to resolve error message Distribution channel is not allowed for sales
    ABAP CCDEF, CCIMP, CCMAC, CCAU, CMXXX这些东东是什么鬼
    有了Debug权限就能干坏事?小心了,你的一举一动尽在系统监控中
    SAP GUI和Windows注册表
  • 原文地址:https://www.cnblogs.com/Chtholly/p/10394469.html
Copyright © 2011-2022 走看看