【模板】——線段樹(求和)

線段樹是一種二叉樹可以用數組來實現
存儲需要的空間爲
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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章