线段树
问题:线段树为什么要开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; }