树状数组(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了;
像离散化处理,二维树状数组。。。