線段樹是一種二叉樹可以用數組來實現
存儲需要的空間爲
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;
}