线段树是一种二叉树可以用数组来实现
存储需要的空间为
n往上的2^n取整再乘以2
如 28 -> 32 x 2 -> 64足够了
我们规定根节点为1
发现每个节点的左子节点为父节点的两倍,右子节点为父节点的两倍加一
void pushup(int rt)//更新父节点
{
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void build(int l, int r, int rt)//rt---root表示当前的节点
{
add[rt] = 0;//
if (l == r)
{
scanf("%d", &sum[rt]);//在这里读入数据
return;
}
int m = (l + r) >> 1;
build(l, m, rt << 1);
build(m + 1, r, rt << 1 | 1);
pushup(rt);
}
void pushdown(int rt, int len)
{
if (add[rt])
{
add[rt << 1] += add[rt];//要加的分到子节点
add[rt << 1 | 1] += add[rt];
sum[rt << 1] += add[rt] * (len - (len >> 1));//子节点加上
sum[rt << 1 | 1] += add[rt] * (len >> 1);//len>>1可能小一
add[rt] = 0;//记得标为0
}
}
void update(int L, int R, int c, int l, int r, int rt)//[L,R]区间数加上c
{
if (L <= l && r <= R)
{
add[rt] += c;
sum[rt] += c*(r - l + 1);//父节点把子节点要加的一次加上
return;
}
pushdown(rt, r-l+ 1);
int m = (l + r) >> 1;
if (L <= m)update(L, R, c, l, m, rt << 1);
if (m < R) update(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)//看区间[l-r]在不在[L,R]内
return sum[rt];
pushdown(rt, r - l + 1);
int m = (l + r) >> 1;
int ret = 0;
if (L <= m) ret += query(L, R, l, m, rt << 1);
if (m < R) ret += query(L, R, m + 1, r, rt << 1 | 1);
return ret;
}