樹狀數組實現線段樹部分功能

P3372 【模板】線段樹 1

要求實現一個數據結構支持區間查詢和區間修改

改裝後的樹狀數組

Sample Code
#include<cstdio>
using namespace std;
#define MAXN 100010
int n,m;long long tree1[MAXN],tree2[MAXN],k,K,pre = 0,now,Left,Right;
inline void update(int left,int right,long long w)
{
	Left = left * w,Right = right * w;
	for(int i = left;i <= n;i += i & -i) tree1[i] += w,tree2[i] += Left;
	for(int i = right;i <= n;i += i & -i) tree1[i] -= w,tree2[i] -= Right;
}
inline long long query(int left,int right) // 查詢
{
	long long ans = 0;
	for(int i = right - 1;i >= 1;i -= i & -i) ans += tree1[i] * right - tree2[i];
	for(int i = left - 1;i >= 1;i -= i & -i) ans -= tree1[i] * left - tree2[i];
	return ans; // sum[right] - sum[left - 1]
}
int main()
{

	scanf("%d%d",&n,&m);
	for(int i = 1;i <= n;i ++)
	{
        scanf("%lld",&now);
		k = now - pre,pre = now,K = k * i,
        tree1[i] += k,tree2[i] += K; 
		for(int j = i + (i & -i);j <= n;j += j & -j) // 因爲l == r所以可以直接build
			tree1[j] += k,tree2[j] += K;
	}
	while(m--)
    {
        int opt;scanf("%d",&opt);
		if(opt == 1)
        {
            int x,y;
			scanf("%d%d%lld",&x,&y,&k);
			update(x,y + 1,k);
		}
        else
        {
            int x,y;
			scanf("%d%d",&x,&y);
			printf("%lld\n",query(x,y + 1));
		}
	}
	return 0;
}

\(tree1\)表示差分數組,\(tree2\)表示差分數組 * 對應序號

由代碼中的定義可得

tree1[1] = a[1];
tree1[2] = a[2] - a[1] + a[1];
tree1[3] = a[3] - a[2];
tree1[4] = a[4] - a[3] + a[3] - a[2] + a[2] - a[1] + a[1];
tree1[5] = a[5] - a[4];

tree2[1] = a[1] * 1;
tree2[2] = (a[2] - a[1]) * 2 + a[1] * 1;
tree2[3] = (a[3] - a[2]) * 3;
tree2[4] = (a[4] - a[3]) * 4 + (a[3] - a[2]) * 3 + (a[2] - a[1]) * 2 + a[1] * 1;
tree2[5] = (a[5] - a[4]) * 5;

化簡得:

tree1[1] = a[1];
tree1[2] = a[2];
tree1[3] = a[3] - a[2];
tree1[4] = a[4];
tree1[5] = a[5] - a[4];

tree2[1] = a[1];
tree2[2] = a[2] * 2 - a[1];
tree2[3] = a[3] * 3 - a[2] * 3;
tree2[4] = a[4] * 4 - a[3] - a[2] - a[1];
tree2[5] = a[5] * 5 - a[4] * 5;

tree2[1] = tree1[1] * 1;
tree2[2] = tree1[2] * 2 - tree1[1];
tree2[3] = tree1[3] * 3;
tree2[4] = tree1[4] * 4 - tree1[3] - tree1[2] * 2 - tree1[1];
tree2[5] = tree1[5] * 5;

\(n = 3\)時有\(\sum\limits_{i=1}^{n}a_i = tree1[1] + tree1[2] + (tree1[3] + tree1[2])\)

tree1[1] + tree1[2] + tree1[3] + tree1[2]
= tree1[1] + 2 * tree1[2] + tree1[3]
= 4 * (tree1[2] + tree1[3]) - 2 * tree1[2] - 3 * tree1[3] + tree1[1]
= 4 * (tree1[2] + tree1[3]) - 2 * tree1[2] + tree1[1] - 3 * tree1[3]
= 4 * (tree1[2] + tree1[3]) - tree2[2] - tree2[3]
= 4 * (tree1[2] + tree1[3]) - (tree2[2] + tree2[3])
= (n + 1) * (tree1[n] + tree1[n - lowbit(n)] + ...) - (tree2[n] + tree2[n - lowbit(n)] + ...)

現在已經見到了其中所蘊含的端倪

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章