zoukankan      html  css  js  c++  java
  • 线段树懒惰点标记更新 hduHDU

    题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=1698

    题意:自行读题

    解题思想:线段树原更新一次只能更新一个叶子节点,并更新此叶子结点以上所有相关的点,当一个区间做相同更新时,叶子节点以上的相关节点不断更新,时间复杂度增加。为节省时间,为每个点添加懒惰标记。自定义节点范围(l,r为求子节点区间和),懒惰点标记(lazy储存变化值),节点和(value节点区间和)。具体实现过程:当更新一个区间时,标记该区间的父亲节点为懒惰区间(祖宗节点的值不用标记,只要更新),同时更新涵盖该区间的节点,而该区间暂时懒得去更新,等下一次更新的区间与原被标记的区间有重合时,则此时将原标记区间往下标记并更新,同时父亲节点因为更新了,没懒惰了,则取消懒惰标记,即懒惰标记传给了子节点,直到重合区间可以以子节点为单位时就可以偷懒不用往下更新了,然后以相同懒惰更新的方式更新这次要更新的区间。

    样例代码图解:

    下图为初始化树,圈内为value值,下标为范围。

     第一次更新后1-5更新为2时后的树,红色为标记点,发现1-5的子节点并没有更新,因为计算总和只和1-5这个点有关,更新这个点就行了。

     第二次更新:在访问点5-9时发现5所在的1-5点被标记了,标记点下推,并更新子节点的值。

     第二次5-9区间更新后的树以及标记的点。

     根据图一下子就可以看出懒惰标记的意思来了,结合代码就方便多了,我画了很久的图QAQ。

    具体代码如下:

    #include<bits/stdc++.h>
    
    const int maxn=100000;
    using namespace std;
    
    struct nodetree{
        int l,r;
        int value,lazy;
    }tree[maxn<<2];
    
    void pushup(int now)
    {
        tree[now].value=tree[now<<1].value+tree[now<<1|1].value;
    }
    
    void build(int l,int r,int n)
    {
        tree[n].l=l;
        tree[n].r=r;
        tree[n].lazy=0;
        if(l==r)
        {
            tree[n].value=1;
            return;
        }
        int mid=(l+r)>>1;
        build(l,mid,n<<1);
        build(mid+1,r,n<<1|1);
        pushup(n);
    }
    void pushdown(int n)
    {
        if(tree[n].lazy!=0)
        {
            tree[n<<1].lazy=tree[n<<1|1].lazy=tree[n].lazy;
            tree[n<<1].value=(tree[n<<1].r-tree[n<<1].l+1)*tree[n<<1].lazy;
            tree[n<<1|1].value=(tree[n<<1|1].r-tree[n<<1|1].l+1)*tree[n<<1|1].lazy;
            tree[n].lazy=0;
        }
    }
    void update(int l,int r,int le,int ri,int n,int va)
    {
        if(r<le||l>ri)
            return;
        if(l>=le&&r<=ri)
        {
            tree[n].lazy=va;
            tree[n].value=tree[n].lazy*(tree[n].r-tree[n].l+1);
            return;
        }
        pushdown(n);
        int mid=(l+r)>>1;
        if(mid>=le) update(l,mid,le,ri,n<<1,va);
        if(mid<ri) update(mid+1,r,le,ri,n<<1|1,va);
        pushup(n);
    }
    int main()
    {
        int T;
        while(~scanf("%d",&T))
        {
            int count=1;
            while(T--)
            {
                int n,t,l,r,va;
                scanf("%d",&n);
                build(1,n,1);
                scanf("%d",&t);
                while(t--)
                {
                    scanf("%d %d %d",&l,&r,&va);
                    update(1,n,l,r,1,va);
                }
                printf("Case %d: The total value of the hook is %d.
    ",count++,tree[1].value);
            }
        }
        return 0;
    }
    

      最后说一下点的value是通过数学计算算出来的。

  • 相关阅读:
    解决Ubuntu19.04无法安装SecureCRT
    gluster学习(二)
    gluster学习(一)
    ansible安装过程遇到的问题
    shell在linux里摇摇晃晃
    ubuntu18.10安装网易云音乐
    MVC Bundle生成的css路径问题
    Vuejs自定义select2指令
    VueJs笔记
    在webAPI的BaseController上使用RoutePrefix
  • 原文地址:https://www.cnblogs.com/wwq-19990526/p/10311109.html
Copyright © 2011-2022 走看看