樹狀數組(Beautiful數據結構)
樹狀數組,又名前綴樹,是很實用的工具,顧名思義樹狀數組(樹型結構的數組,一種存儲方式)
!!!!!由子樹構成的大樹,大數;
上圖就是其形象的結構圖樣。A[1]->C[1] ; C[2]->A[1]+A[2] ; C[3]->A[3] ; C[4]->C[2]+C[3]->A[1]+A[2]+A[3]+A[4] ; C[5]->A[5] ; C[6]->A[5]+A[6] ; C[7]->A[7] ; C[8]->A[1]+…+A[8]
注意節點區間和變成了1,2,4,8,16…
此時找一下規律
以5 爲例子二進制表示0101,若減去0001—>變成0100,4節點。若加上0001---->變成0110再加上0010---->變成1000,8節點。發現要是提取了一個數的最後一位,加上它或者減去它,正好就是二進制中的1,2,4,8,16…
這只是數字遊戲罷了,只要找到末尾的1,就能依次到1,10,100,100000000000,因爲這是我們要建立的樹而已。由子樹到參天大樹。
現在就來就找數字的最後一位1,
#define lowbit(x) x&(-x) //每一次將其寫在代碼前面方便使用;
就拉一道模版題出來吧:
題意很簡單,就是有N個數,兩種操作1.查詢任意區間和。2.在任意位置加或減去一個數。
代碼給詳解:
相對於線段樹,樹狀數組真的是性價比超高了呢《----》
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#define lowbit(x) x&(-x) //超方便的取位方法,0不能用啊,不然就死循環了。
using namespace std;
const int N=1e5+55;
int tree[N]; //數組tree,樹狀的結構,不開long long 見祖宗。。。。。
void add(int x, int val) //前綴和;
{
if(!x) return ;
while(x<=N){
tree[x]+=val;
x+=lowbit(x); // x本身也加上了哦 //將數據依次向上推入,加加加加,是向上的;
}
}
int search_tree(int x)
{
int ans=0; //將所有子樹都加到位好吧;
while(x>0){
ans+=tree[x];
x-=lowbit(x); //需要注意x位置的值也算入了 //向下取和,建議手動模擬一遍印象更深刻德瑪;
}
return ans;
}
int main()
{
int n,m,i,x,y,val,k,sum1,sum2;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%d",&val);
add(i,val); //加加加入;
}
for(i=0;i<m;i++){
scanf("%d",&k);
if(k==1){
scanf("%d%d",&x,&y);
sum1=search_tree(x-1); //x本身也加上了故爲(x-1);
sum2=search_tree(y);
printf("%d\n",sum2-sum1);
}
else{
scanf("%d%d",&x,&val);
add(x,val);
}
}
return 0;
}
若是實際應用還牽扯到其他知識點,多做些題就OK了;
像離散化處理,二維樹狀數組。。。