0分求调orz

P3372 【模板】线段树 1

Shigongcheng001 @ 2023-11-25 17:22:15


#include<bits/stdc++.h>
using  namespace std;
#define N 1000005
#define ll long long
#define ls o*2
#define rs o*2+1

ll n,m,x,y,k,flag;
ll a[N];

struct tree{
    ll l,r;//左,右子节点 
    ll point;//节点值 
    ll add;//懒标记值 
};
tree t[4*N];

 void build(ll o,ll l,ll r){
    t[o].l =ls;
    t[o].r =rs;
    if(l==r){
        t[o].point=a[l];
        return;
     }
     ll mid=l+r>>1;
     build(ls,l,mid);
     build(rs,mid+1,r);
     t[o].point =t[ls].point +t[rs].point ;//更新节点值 
 }

 void spread(ll o){
    if(t[o].add ){
        t[ls].point +=t[o].add *(t[ls].r-t[ls].l +1);
        t[rs].point +=t[o].add *(t[rs].r-t[rs].l+1);
        t[ls].add +=t[o].add ;
        t[rs].add +=t[o].add ;
        t[o].add =0;
     }
 }

 void change(ll o,ll x,ll y,ll z){
    if(x<=t[o].l &&y>t[o].r ){
      t[o].add +=z;
      t[o].point +=z*(t[o].r -t[o].l +1);
      return ;
    }
    spread(o);
    ll mid=t[o].l +t[o].r >>1;
    if(x<=mid)change(mid,x,y,z);
    if(y>mid)change(mid+1,x,y,z);
    t[o].point =t[ls].point +t[rs].point ;//更新节点值 

 }

 ll ask(ll o,ll x,ll y){
    if(x<=t[o].l &&y>t[o].r ){
        return t[o].point ;
     }
    ll ans=0;
    ll mid=t[o].l +t[o].r >>1;  
    if(x<=mid) ans+=ask(mid,x,y);
    if(y>mid) ans+=ask(mid+1,x,y);//查到的完全包含的节点的返回 

    return ans;//查到的不完全包含的节点的返回  
 }

int main(){
cin>>n>>m;
for(ll i=1;i<=n;i++){
    cin>>a[i];
}
build(1,1,n);   
    for(ll i=1;i<=m;i++){
        cin>>flag;
        if(flag==1){
            cin>>x>>y>>k;
            change(1,x,y,k);
        }
        if(flag==2){
            cin>>x>>y;
            cout<<ask(1,x,y)<<endl;
        }
    }

    return 0;
}

by 0907_WDS_0731 @ 2023-11-28 19:18:47

#include<bits/stdc++.h>
using  namespace std;
#define N 1000005
#define ll long long
#define ls o*2
#define rs o*2+1

ll n,m,x,y,k,flag;
ll a[N];

struct tree{
    ll l,r;//左,右子节点 
    ll point;//节点值 
    ll add;//懒标记值 
};
tree t[4*N];

void build(ll o,ll l,ll r){
//  t[o].l =ls;
//  t[o].r =rs;
    t[o].l =l;
    t[o].r =r;
    if(l==r){
        t[o].point=a[l];
        return;
    }
    ll mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    t[o].point =t[ls].point +t[rs].point ;//更新节点值 
}

void spread(ll o){
    if(t[o].add ){
        t[ls].point +=t[o].add *(t[ls].r-t[ls].l +1);
        t[rs].point +=t[o].add *(t[rs].r-t[rs].l+1);
        t[ls].add +=t[o].add ;
        t[rs].add +=t[o].add ;
        t[o].add =0;
    }
}

void change(ll o,ll x,ll y,ll z){
//  if(x<=t[o].l &&y>t[o].r ){
    if(x<=t[o].l &&y>=t[o].r ){
        t[o].add +=z;
        t[o].point +=z*(t[o].r -t[o].l +1);
        return ;
    }
    spread(o);

    ll mid=t[o].l +t[o].r >>1;
//  if(x<=mid)change(mid,x,y,z);
//  if(y>mid)change(mid+1,x,y,z);
    if(x<=mid)change(ls,x,y,z);
    if(y>mid)change(rs,x,y,z);
    t[o].point =t[ls].point +t[rs].point ;//更新节点值 

}

ll ask(ll o,ll x,ll y){
    if(x<=t[o].l &&y>=t[o].r )
        return t[o].point ;
    spread(o);
    ll ans=0;
    ll mid=t[o].l +t[o].r >>1;  
//  if(x<=mid) ans+=ask(mid,x,y);
//  if(y>mid) ans+=ask(mid+1,x,y);//查到的完全包含的节点的返回 
    if(x<=mid)ans+=ask(ls,x,y);
    if(y>mid)ans+=ask(rs,x,y);
    return ans;//查到的不完全包含的节点的返回  
}

int main(){
    cin>>n>>m;
    for(ll i=1;i<=n;i++){
        cin>>a[i];
    }
    build(1,1,n);   
    for(ll i=1;i<=m;i++){
        cin>>flag;
        if(flag==1){
            cin>>x>>y>>k;
            change(1,x,y,k);
        }
        if(flag==2){
            cin>>x>>y;
            cout<<ask(1,x,y)<<endl;
        }
    }

    return 0;
}
  1. 建树时,也就是build函数,自己的左节点和右节点是传过来的l,r
  2. 在change与ask函数中再次进行传值的函数的下标o应该是自己的左右节点,即ls,rs
  3. 并且在ask函数中也要进行懒标记下传 并建议参考题解,于你写的相似

|