zoukankan      html  css  js  c++  java
  • 可持久化线段树

    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


    【可持久化线段树???主席树???】

    有人说可持久化线段树和主席树是一样的,又有人说,这两个不一样,不过无所谓了,反正就是实现空间的优化,同时可以查询以前的版本,大概我就知道这两个功能。每次修改的时间复杂度和增加的空间都是logn的,所以就很优越了。

    那么这个优越的数据结构是如何实现的,其实我第一次看到这个高大上的算法名字时,内心是畏惧的,但后来慢慢一看一些大佬的博客,发现还是不是很难,也就是在线段树的基础上增加了一点小技巧,所以新学者不要担心,我这么蠢的都学会了,大家就不虚了。

    首先我们还是来看看这张经典的可持久化线段树的图解

    比如我们现在要修改第3个点的值,我们需要修改什么点呢,就是第3个点的所有祖先节点(图中红色节点),因为那些节点管理的区间包括第3个点(我们就不用重新建树了),当然我们更不能把这些点直接改了,因为以后可能还要查询这个版本。

    所以我们就对于每个要被修改的节点,新建一个copy节点,来代替新的版本的这个节点,当然如果没有修改的节点依旧保留原来的连接方式。

    然后我们就发现,如果我们要查询第k个版本的区间信息,那我们就从第k个根节点开始查询就可以了,发现是不是很简单啊,就是复制节点+从某版本根节点开始查询。

    【代码实现】

     1 #include<cstdio>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=1e5+5;
     5 struct sd{
     6     int l,r,maxx,son[2];
     7 }t[20*maxn+5];
     8 int root[maxn],tot,cnt;
     9 void update(int v)
    10 {
    11     int ls=t[v].son[0],rs=t[v].son[1];
    12     t[v].maxx=max(t[ls].maxx,t[rs].maxx);
    13 }
    14 void build(int &v,int l,int r)
    15 {
    16     cnt++,v=cnt,t[v].l=l,t[v].r=r;
    17     if(l==r) {scanf("%d",&t[v].maxx);return;}
    18     int mid=(l+r)/2;
    19     build(t[v].son[0],l,mid);
    20     build(t[v].son[1],mid+1,r);
    21     update(v);
    22 }
    23 int num;
    24 void change(int v,int pos,int u)
    25 { 
    26     if(t[v].l==t[v].r&&t[v].l==pos)
    27     {t[v].maxx=u;return;}
    28     int mid=(t[v].l+t[v].r)/2,ls=t[v].son[0],rs=t[v].son[1];
    29     if(pos<=mid)
    30     {
    31         cnt++,t[cnt]=t[ls],t[v].son[0]=cnt;
    32         change(cnt,pos,u);
    33     }
    34     else
    35     {
    36         cnt++,t[cnt]=t[rs],t[v].son[1]=cnt;
    37         change(cnt,pos,u);
    38     }
    39     update(v);
    40 }
    41 int ask(int v,int l,int r)
    42 {
    43     if(t[v].l==l&&t[v].r==r)
    44     return t[v].maxx;
    45     int mid=(t[v].l+t[v].r)/2,ls=t[v].son[0],rs=t[v].son[1];
    46     if(r<=mid) return ask(ls,l,r);
    47     else if(l>mid) return ask(rs,l,r);
    48     else return max(ask(ls,l,mid),ask(rs,mid+1,r));
    49 }
    50 int main()
    51 {
    52     int n,m;
    53     scanf("%d%d",&n,&m);
    54     build(root[++tot],1,n);
    55     for(int i=1;i<=m;i++)
    56     {
    57         int ord;
    58         scanf("%d",&ord);//printf("[%d]",ord);
    59         if(ord==0)
    60         {
    61             int k,l,r;
    62             scanf("%d%d%d",&k,&l,&r);
    63             printf("%d
    ",ask(root[k],l,r));
    64         }
    65         else
    66         {
    67             int k,pos,u;
    68             scanf("%d%d%d",&k,&pos,&u);
    69             root[++tot]=++cnt;t[cnt]=t[root[k]];
    70             change(root[tot],pos,u);
    71         }
    72     }
    73     return 0;
    74 }
  • 相关阅读:
    微信小程序---app.json中设置背景色不生效解决办法
    给网站设置ICO图标
    ajax事件(五)
    ajax关于主流中的异类:应对Opera(四)
    dashboard
    tomcat 清理日志
    jQuery datatable
    php wampserver 80 端口无法开启的解决方法
    mysql 行列转换
    jQuery-2.1.4.min.js:4 Uncaught TypeError: Illegal invocation
  • 原文地址:https://www.cnblogs.com/genius777/p/8987574.html
Copyright © 2011-2022 走看看