线段树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;
}

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

原文地址:https://www.cnblogs.com/mudrobot/p/13331131.html