萌新刚学OI,求助线段树板子
查看原帖
萌新刚学OI,求助线段树板子
485688
想吃小熊饼干楼主2021/8/22 12:35

rt,#8#9#10 WA。

code:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#define N 100000
using namespace std;
int a[N],Sum[N<<2],Add[N<<2];//开4倍大的数组构建线段树
void Pushup(int rt){Sum[rt]=Sum[rt<<1]+Sum[rt<<1|1];}//向上传值
void PushDown(int rt,int ln,int rn)//向下传懒标记并更新值,ln为左子树结点数,rn为右子树结点数
{
    if(Add[rt])//当懒标记不为0时
    {
        Add[rt<<1]+=Add[rt];//将懒标记传给左孩子
        Add[rt<<1|1]+=Add[rt];//将懒标记传给右孩子
        Sum[rt<<1]+=Add[rt]*ln;//更新左子树的值
        Sum[rt<<1|1]+=Add[rt]*rn;//更新右子树的值
        Add[rt]=0;//将当前结点的懒标记置为0
    }
}
void Build(int l,int r,int rt)//建树
{
    if(l==r)//遍历到叶结点时直接存数据
    {
        Sum[rt]=a[l];
        return ;
    }
    int m=(l+r)>>1;
    Build(l,m,rt<<1);//建左子树
    Build(m+1,r,rt<<1|1);//建右子树
    Pushup(rt);//向上传值
}
void Update1(int L,int C,int l,int r,int rt)//点修改,a[L]+=C
{
    if(l==r)//当为叶节点时直接更新结点的值
    {
        Sum[rt]+=C;
        return ;
    }
    int m=(l+r)>>1;
    if(L<=m)Update1(L,C,l,m,rt<<1);//若结点在左子树,更新左子树
    else Update1(L,C,m+1,r,rt<<1|1);//若结点在右子树,更新右子树
    Pushup(rt);//向上传值
}
void Update2(int L,int R,int C,int l,int r,int rt)//区间修改
{
    if(L<=l&&R>=r)//当要修改的区间覆盖结点区间时,当前结点Sum值直接加上结点数*C
    {
        Sum[rt]+=C*(r-l+1);
        Add[rt]+=C;
        return ;
    }
    int m=(l+r)>>1;
    PushDown(rt,m-l+1,r-m);//向下传递懒标记并更新值
    if(L<=m)Update2(L,R,C,l,m,rt<<1);//更新左子树
    if(R>m)Update2(L,R,C,m+1,r,rt<<1|1);//更新右子树
    Pushup(rt);//向上传值
}
int Query(int L,int R,int l,int r,int rt)//区间访问
{
    if(L<=l&&R>=r)//当要修改的区间覆盖结点区间时,直接访问
    {
        return Sum[rt];
    }
    int m=(l+r)>>1;
    PushDown(rt,m-l+1,r-m);//避免懒标记没有处理
    int ans=0;
    if(L<=m)ans+=Query(L,R,l,m,rt<<1);//返回左子树的值
    if(R>m)ans+=Query(L,R,m+1,r,rt<<1|1);//返回右子树的值
    return ans;
}
int Findmax(int L,int R,int l,int r,int rt)//查询区间最大值,是找最大值的区间,即最长的线段
{
    if(L<=l&&R>=r)//当要修改的区间覆盖结点区间时,直接访问
    {
        return Sum[rt];
    }
    int m=(l+r)>>1;
    int ans=0;
    if(L<=m)ans=max(ans,Findmax(L,R,l,m,rt<<1));//求左子树最大值区间
    if(R>m)ans=max(ans,Findmax(L,R,m+1,r,rt<<1|1));//求右子树最大值区间
    return ans;
}
int main()
{
    int n,m,ope,L,C,R;
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    Build(1,n,1);//建树
    for(int i=1;i<=m;i++)
    {
        cin>>ope>>L>>R;
        if(ope==1)
        {
            cin>>C;
            Update2(L,R,C,1,n,1);
        }
        else if(ope==2)cout<<Query(L,R,1,n,1)<<endl;
    }
    return 0;
}
2021/8/22 12:35
加载中...