樹狀陣列實現線段樹區間修改區間查詢功能

2021-09-01 13:20:44 字數 1395 閱讀 3628

已知樹狀陣列區間修改單點查詢時tree陣列中存放的是相鄰差值,那麼區間修改的基礎我們已經有了,但只能支援單點查詢,需要再構造區間查詢功能,暴力累加是不可能考慮的,而樹狀陣列的區間查詢是利用字首和實現的,tree陣列中儲存的是字首和。所以我們需要在單點查詢的基礎上再構造乙個字首和。我們需要整理一下查詢

第k個數 a[k]=tree[1]+tree[2]+tree[3]+tree[4]+...+tree[k]

第k的字首和為 s[k]=a[k]+a[k-1]+....+a[1]

即為 s[k]=(tree[1]+tree[2]+...tree[k])+(tree[1]+tree[2]+...+tree[k-1])+...+(tree[1])

拆分合併即為 s[k]=tree[1]*k+tree[2]*(k-1)+....+tree[k]*1

雖然這是乙個和的形式,但是無法直接構造,因為與當前位置無直接關係,需要構造乙個。

轉化成包含普通字首和的形式

s[k]=k*(tree[k]+tree[k-1]+...+tree[1])-(tree[k]*(k-1)+tree[k-1]*(k-2)+tree[k-2]*(k-3)+....+tree[1]*0)

前部分可以直接使用tree陣列查詢,觀察後部分為tree[i]*(i-1)的字首和形式,所以另設定乙個樹狀陣列p來儲存。

初始化為 add(i,(i-1)*y)     y為原陣列的差分即當前元素與上乙個元素的差值即tree[y]

區間修改時無異  add(x,k*(y-1))   add(y+1,-k*y)

所以所求的區間(x,y)和為 【y*y的tree字首和-(x-1)*(x-1tree的字首和)】-【y的p字首和-x的p字首和】

(y*sum(y,tree)-(x-1)*sum(x-1,tree))-(sum(y,p)-sum(x-1,p))

實際上就是利用字首和構造。不能就轉化成字首和形式

**如下:

#include#include#include#include#includeusing namespace std;

#define inf 0x3f3f3f3f

#define ll long long

#define per(i,a,b) for(int i=a;i<=b;++i)

ll int n,m,tree[2000010],p[2000010];

ll int lowbit(ll int k)

void add(ll int x,ll int k,int fag)

}ll int sum(ll int x,int fag)

return s;

}int main()

per(i,1,m)

if(a==2)

}return 0;

}

樹狀陣列 區間修改,區間查詢

也許更好的閱讀體驗 好東西,以後可以不打線段樹了 本篇假定讀者都會最基礎的兩種樹狀陣列,即區改單查和單改區查 思考如何維護乙個區間的值,想到了差分 對乙個差分陣列做一次字首和可以得到每個位置的值 再對每個位置累加一下就是乙個區間的值 公式化的講,就是 設差分陣列為 c 則每個位置的值 val i s...

樹狀陣列區間修改區間查詢

題面 首先,我們要推乙個柿子。displaystyle sum a i 把a i 用差分陣列表示出來,就可以寫成 displaystyle sum sum d i 我們考慮一下,每個d i 出現的次數是一定的。那我們可以換一下列舉順序,先列舉d i 在列舉他出現的次數,就可以變成 displayst...

樹狀陣列高階 區間修改 區間查詢

區間修改與區間查詢 今天老糊塗了,樹狀陣列忘記了,基本的只要單點修改 區間查詢功能,如果要進行區間加操作,需要把樹狀陣列進行改造。我們首先來回顧樹狀陣列的功能 lowbit x x 返回二進位制最低位 1的值 比如 x 1010 那麼lowbit值為2 x lowbit x 把最後一位二進位制最低位...