• 线段树1对于Pushdown的理解


    线段树1对于Pushdown的理解

    线段树1是一个区间修改和区间求值的题,他相当于以前的线段树——区间求值和单点修改和区间修改和单点求值,产生了本质上的一些区别,最主要的就在于Pushdown上的区别,现在我们就来区分一下。

    1、线段树练习——单点修改和区间求值

    这个主要考察的就是线段树最主要的三个步骤 建树(Buildtree) 修改(modify) 查询(query)本题难度不大,就是让OIER们熟悉一下线段树这个数据结构。因此先介绍一下基本操作。

    1、建树 (Buildtree)

        void buildTree(int &k,int l,int r)
        {
            //初始化一个管理[l,r]的节点 , 下标为k 
            k=++cnt;//k = cnt+1; cnt++;
            node[k].l=l;node[k].r=r;//初始化[l,r] 
            if(l==r)
            {
                //没有儿子了 
                node[k].sum=ini[r];
            }
            else
            {
                //我是爸爸 
                int mid=( node[k].l+node[k].r )/2;//儿子的左右分界 
                buildTree(node[k].son[L],l,mid);//调用完后 左右儿子下表就可以被储存 
                buildTree(node[k].son[R],mid+1,r); 
                node[k].sum=node[ node[k].son[L] ].sum + node[ node[k].son[R] ].sum;//计算当前节点的和 
            }
        }
    

    2、修改(modify)

        void modify(int k,int pos,int val)
        {
            //修改  把ini[pos]修改为val 
            if(node[k].l==node[k].r)
            {
                //儿子!  l==r l==pos
                node[k].sum+=val;
                ini[pos]+=val;//好像没有用 
            }
            else
            {
                int mid=( node[k].l+node[k].r )/2;//儿子的左右分界 
                if( pos<=mid ) modify(node[k].son[L],pos,val);//这个点在左儿子 
                else modify(node[k].son[R],pos,val);
                node[k].sum=node[ node[k].son[L] ].sum + node[ node[k].son[R] ].sum;//计算当前节点的和 
            }
        }
    

    3、查询(query)

        long long query(int k,int ql,int qr)
        {
            //查询[ql,qr]☣
            if(node[k].l==ql && node[k].r==qr)
            {
                return node[k].sum;
            }
            else
            {
                int mid=( node[k].l+node[k].r )/2;//儿子的左右分界 
                if(qr<=mid) return query(node[k].son[L],ql,qr);//全在左儿子 
                else if(ql>=mid+1) return query(node[k].son[R],ql,qr);//全在右儿子 
                else return query(node[k].son[L],ql,mid) + query(node[k].son[R],mid+1,qr);//分开了 
            }
        }
    

    请记住query查询一定要用“long long”
    有了以上的帮助后,再加上自己对Pushdown的理解,于是luogu上的线段树1就已经可以干掉了。

    代码如下:

        #include<cstdio>
        #include<cstring>
        using namespace std;
        const int N=100005;
        struct sd{
            int l,r,son[2];
            long long add,sum;
        }node[N*2];
        int root,cnt=0;
        int ini[N];
        void Buildtree(int &k,int l,int r)
        {
            k=++cnt;
            node[k].l=l;
            node[k].r=r;
            if(l==r)
            {
                node[k].sum=ini[l];
            }
            else
            {
                int mid=(l+r)/2;
                Buildtree(node[k].son[0],l,mid);
                Buildtree(node[k].son[1],mid+1,r);
                node[k].sum=node[node[k].son[0]].sum+node[node[k].son[1]].sum;
            }
        }
        void pushdown(int k)
        {
            node[node[k].son[0]].add+=node[k].add;
            node[node[k].son[1]].add+=node[k].add;
            node[node[k].son[0]].sum+=node[k].add*(node[node[k].son[0]].r-node[node[k].son[0]].l+1);
            node[node[k].son[1]].sum+=node[k].add*(node[node[k].son[1]].r-node[node[k].son[1]].l+1);
            node[k].add=0;//☣
        }
        void modify(int k,int ql,int qr,int val)
        {
            if(ql==node[k].l&&qr==node[k].r)
            {
                pushdown(k);
                node[k].add+=val;
                node[k].sum+=(node[k].r-node[k].l+1)*node[k].add;
            }
            else
            {
                pushdown(k);
                int mid=(node[k].l+node[k].r)/2;
                if(mid>=qr) modify(node[k].son[0],ql,qr,val);
                else if(mid<ql) modify(node[k].son[1],ql,qr,val);
                else
                {
                    modify(node[k].son[0],ql,mid,val);
                    modify(node[k].son[1],mid+1,qr,val);
                }
                node[k].sum=node[node[k].son[0]].sum+node[node[k].son[1]].sum;
            }
        }
        long long query(int k,int ql,int qr)
        {
            if(ql==node[k].l&&qr==node[k].r)
            {
                return node[k].sum;
            }
            else
            {
                pushdown(k);
                int mid=(node[k].l+node[k].r)/2;
                if(mid>=qr) return query(node[k].son[0],ql,qr);
                else if(mid<ql) return query(node[k].son[1],ql,qr);
                else
                {
                    return query(node[k].son[0],ql,mid)+query(node[k].son[1],mid+1,qr);
                }
            }
        }
        int main()
        {
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i)
            {
                scanf("%d",&ini[i]);
            }
            Buildtree(root,1,n+3);
            int a,b,c,d;
            for(int i=1;i<=m;++i)
            {
                scanf("%d",&d);
                if(d==1)
                {
                    scanf("%d%d%d",&a,&b,&c);
                    modify(root,a,b,c);
                }
                else
                {
                    scanf("%d%d",&a,&b);
                    printf("%lld
    ",query(root,a,b));
                }
            }
            return 0;
        }
    ***Pushdown方面展示:***
        void pushdown(int k)
            {
                node[node[k].son[0]].add+=node[k].add;
                node[node[k].son[1]].add+=node[k].add;
                node[node[k].son[0]].sum+=node[k].add*(node[node[k].son[0]].r-node[node[k].son[0]].l+1);
                node[node[k].son[1]].sum+=node[k].add*(node[node[k].son[1]].r-node[node[k].son[1]].l+1);
                node[k].add=0;
            }
    

    线段树2有一点耗脑力,需要后续思考!
    后续持续更新······

    这里有一个思路比较清晰的线段树:

    #include<bits/stdc++.h>
    #define LL long long
    #define N 100005
    using namespace std;
    LL root,m,n,cnt=0,ini[N];
    struct sd{
        LL son[2],l,r,sum,add;
    }node[N*3];
    void update(LL k){node[k].sum=node[node[k].son[0]].sum+node[node[k].son[1]].sum;}
    void add(LL k,LL val)
    {
        node[k].add+=val;
        node[k].sum+=val*(node[k].r-node[k].l+1);
    }
    void pushdown(LL k)
    {
        add(node[k].son[0],node[k].add);
        add(node[k].son[1],node[k].add);
        node[k].add=0;
    }
    void Buildtree(LL &k,LL l,LL r)
    {
        cnt++;k=cnt;node[k].l=l;node[k].r=r;
        if(l==r)node[k].sum=ini[l];
        else
        {
            LL mid=(l+r)/2;
            Buildtree(node[k].son[0],l,mid);
            Buildtree(node[k].son[1],mid+1,r);
            update(k);
        }
    }
    void modify(LL k,LL l,LL r,LL val)
    {
        if(node[k].l==l&&node[k].r==r) add(k,val);
        else
        {
            pushdown(k);
            LL mid=(node[k].l+node[k].r)/2;
            if(r<=mid) modify(node[k].son[0],l,r,val);
            else if(l>mid) modify(node[k].son[1],l,r,val);
            else modify(node[k].son[0],l,mid,val),modify(node[k].son[1],mid+1,r,val);
            update(k);
        }
    }
    LL query(LL k,LL l,LL r)
    {
        if(node[k].l==l&&node[k].r==r) return node[k].sum;
        else
        {
            pushdown(k);
            LL mid=(node[k].r+node[k].l)/2;
            if(r<=mid) return query(node[k].son[0],l,r);
            else if(l>mid) return query(node[k].son[1],l,r);
            else return query(node[k].son[0],l,mid)+query(node[k].son[1],mid+1,r);
        }
    }
    int main()
    {
        scanf("%lld%lld",&n,&m);
        for(int i=1;i<=n;++i) scanf("%lld",&ini[i]);
        Buildtree(root,1,n);LL a,b,c,d;
        for(int i=1;i<=m;++i)
        {
            scanf("%lld%lld%lld",&a,&b,&c);
            if(a==1) scanf("%lld",&d),modify(root,b,c,d);
            if(a==2) printf("%lld
    ",query(root,b,c));
        }
        return 0;
    }
    

    指针版的线段树戳这里☞指针版的线段树

  • 相关阅读:
    CAD图形引擎库VectorDraw
    基于COM的矢量图像控件VectorDraw
    [转]电子表格Spread 7.0线上发布会
    ProEssentials图表教程汇总
    几种JS 引擎介绍(不同浏览器有不同的引擎)
    我的 学习链接
    ExtJS 2.3版 源代码的解析(转)
    javascript调试原理(一)(转)
    使用GoogleCode SVN服务
    javascript调试原理(二) 模拟实现 (转)
  • 原文地址:https://www.cnblogs.com/mudrobot/p/13331131.html
Copyright © 2020-2023  润新知