线段树

①建树---o(n)

②单点修改---o(logn)

③区间查询---o(logn)

④区间修改---o(logn)

//线段树
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define lc p<<1
#define rc p<<1|1

const int N=500005;
int n,arr[N];
typedef struct node{
    int l,r,sum,add;    //区间修改还需要第四个变量add,表示标记
}node;
node tree[4*N];

void build(int p,int l,int r){          //根节点 和 区间的左右边界         o(n)
    tree[p]={l,r,arr[l]};
    if(l==r) return;            //是叶子节点则返回
    int mid=l+(r-l)/2;
    build(p<<1,l,mid);   //p<<1  ==  p*2
    build(p<<1|1,mid+1,r);  //p<<1|1  ==  p*2+1
    tree[p].sum=tree[ p<<1 ].sum+tree[ p<<1|1 ].sum;  //父节点的sum 等于 左右孩子的sum 的和
}

void update1(int p,int x,int k){         //单点修改    //根节点p 修改位置x 增加的值k        o(logn)
    if(tree[p].l==x&&tree[p].r==x){         //找到修改位置x
        tree[p].sum+=k;
        return;
    }
    int mid=tree[p].l+( tree[p].r-tree[p].l )/2;
    if(x<=mid) update1( p<<1,x,k );
    if(x>mid) update1( p<<1|1,x,k );
    tree[p].sum=tree[ p<<1 ].sum+tree[ p<<1|1 ].sum;
}

int query(int p,int x,int y){           //根节点p  查询区间[x,y]的值             o(logn)
    if(x<=tree[p].l&&tree[p].r<=y) return tree[p].sum;  //完全覆盖则返回
    int mid=tree[p].l+( tree[p].r-tree[p].l )/2;
    int sum=0;
    if(x<=mid) sum+=query( p<<1,x,y );          //与左子树重叠就递归访问左子树
    if(y>mid)  sum+=query( p<<1|1,x,y );        //与右子树重叠就递归访问右子树
    return sum;
}

//区间修改!              o(logn)
void pushup(int p){   //向上更新
    tree[p].sum=tree[lc].sum+tree[rc].sum;
}
void pushdown(int p){   //向下更新
    if(tree[p].add){        //非0
        tree[lc].sum+=tree[p].add*( tree[lc].r-tree[lc].l+1 );  //左孩子区间宽度*k
        tree[rc].sum+=tree[p].add*( tree[rc].r-tree[rc].l+1 );  //右孩子区间宽度*k
        tree[lc].add+=tree[p].add;
        tree[rc].add+=tree[p].add;
        tree[p].add=0;
    }
}

void update2(int p,int x,int y,int k){      //根节点p  修改的区间[x,y]  增加的值k
    if(x<=tree[p].l&&tree[p].r<=y){         //完全覆盖则修改
        tree[p].sum+=( tree[p].r-tree[p].l+1 )*k; //区间宽度*k
        tree[p].add+=k;  //标记
        return;
    }
    int mid=( tree[p].l+tree[p].r )>>1;     //不覆盖则裂开
    pushdown(p);
    if(x<=mid) update2(lc,x,y,k);
    if(y>mid) update2(rc,x,y,k);
    pushup(p);
}

void solve(){                                       //线段树模板
    int m;
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>arr[i];
    build(1,1,n);
    while(m--){
        int op;
        cin>>op;
        if(op==1){
            int x,k;
            cin>>x>>k;
            update1(1,x,k);
        }
        else{
            int x,y;
            cin>>x>>y;
            cout<<query(1,x,y)<<"\n";
        }
    }
}

signed main() {
    ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
    solve();
    return 0;
}

 

posted @ 2023-11-14 20:54  osir  阅读(0)  评论(0编辑  收藏  举报