线段树

问题:线段树为什么要开4倍空间

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=100010;
int q[N];

struct node{
    int l,r;//tree[i].l和tree[i].r分别表示这个点代表的线段的左右下标
    int sum;//tree[i].sum表示这个节点表示的线段和
}tree[N<<2];  //开四倍空间

void pushup(int u){        //更新函数
    tree[u].sum=tree[u<<1].sum+tree[u<<1|1].sum; //父节点的和等于两个子节点之和
}

//一个节点为x 它的父节点为x/2(x>>1) 左儿子2x(x<<1) 右儿子2x+1(x<<1|1)
void build(int u,int l,int r){
    if(l==r){     //左端点等于右端点,即为叶子节点,直接赋值即可
        tree[u].l=l;
        tree[u].r=r;
        tree[u].sum=q[l];
    }
    else{
        tree[u].l=l;
        tree[u].r=r;
        int mid=(l+r)>>1;    //mid则为中间点,左儿子的结点区间为[l,mid],右儿子的结点区间为[m+1,r]
        build(u<<1,l,mid);    //递归构造左儿子结点
        build(u<<1|1,mid+1,r);    //递归构造右儿子结点
        pushup(u);    //更新父节点
    }
}

//区间查询
int query(int u,int l,int r){    //u为结点下标, [l,r]即为要查询的区间
    if(tree[u].l>=l&&tree[u].r<=r)    //如果当前结点的区间包含于(⊆)要查询的区间内,则返回结点信息且不需要往下递归
        return tree[u].sum;

    int sum=0;    //返回值变量,根据具体线段树查询的什么而自定义
    int mid=(tree[u].l+tree[u].r)>>1;    //mid则为中间点,左儿子的结点区间为[l,mid],右儿子的结点区间为[mid+1,r]
    if(l<=mid)   //先找和左边无交集
        sum=query(u<<1,l,r); //左儿子
    if(r>mid)   //再找和右边无交集
        sum+=query(u<<1|1,l,r); //加上右儿子

    return sum;    //返回当前结点得到的信息

}

//单点修改
void modify(int u,int p,int v){    //u为结点下标,p为修改的点,v为要加上的值
    if(tree[u].l==tree[u].r)    //左端点等于右端点,即为叶子结点,直接加上v即可
        tree[u].sum+=v;    //线段树数组都得到修改
    else{
        int mid=(tree[u].l+tree[u].r)>>1;    //mid则为中间点,左儿子的结点区间为[l,mid],右儿子的结点区间为[mid+1,r]
        if(p<=mid)   //如果需要更新的结点在左子树区间
            modify(u<<1,p,v); 
        else if(p>=mid+1)    //如果需要更新的结点在右子树区间
            modify(u<<1|1,p,v);

        pushup(u);    //更新父节点的值
    }
}

int main(){
    int n,m;
    int k,a,b;
    cin>>n>>m;
    for(int i=1;i<=n;i++) scanf("%d",&q[i]);

    build(1,1,n);

    for(int i=0;i<m;i++){
        scanf("%d%d%d",&k,&a,&b);
        if(k==0) printf("%d\n",query(1,a,b));
        if(k==1) modify(1,a,b);
    }
    return 0;
}