标签:hid isp 树状数组 技术分享 .com onclick 分享 mes while
树状数组是一种数据结构,支持一些区间操作,比线段树好写,同样也比线段树的功能少一些。
先来看一张图(摘自百度百科)
树状数组就是这个样子的,但是树状数组的空间复杂度是O(n)的,它不像线段树那样每个节点的信息都上传的父亲去保存,他是由某一位来保存前一段区间的信息,比如说和。那么是哪一位又是保存多长的区间那?这就到了数状数组的主角lowbit上场了,lowbit是一个很简单又很复杂的东西,说它简单是因为写起来非常的简单,说它复杂是因为理解起来比较麻烦,lowbit(x)的功能是求出来x的二进制中最后一个1是多少,举个例子lowbit(7)=1,因为7的二进制是111,它的最后一个1是1,而lowbit(6)=2,因为6的二进制是110,它的最后一个1是2.
有的讲树状数组的是把lowbit的原理讲了一遍的,个人感觉没用其实是窝不会,只需要记得lowbit(x)的求法是x&(-x)就好了,然后树状数组的第i位记录的就是从i-lowbit(i)+1开始到i这一段的信息,也就是从i往前lowbit(i)那么长,总之这样沿着lowbit就可以做到不重不漏了。
树状数组最基本的操作就是点修改区间查询,点修改区间查询和区间修改点查询。
点修改不只是要修改一个点,还要把记录了这个点的信息的那些点也修改了,这时还是要沿着lowbit走,当前点不断的加lowbit,每次到的点都修改一下,而区间查询就更容易了,如果查询区间是[l,r],那么久查询一下[1,r],在查询一下[1,l-1]然后相减久ok了,然后查询就是沿着lowbit减,把每一位的数加起来,好比查询[1,7],就查7,[5,6],[1,4]就可以了。
模板:https://www.luogu.org/problemnew/show/P3374
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int maxn=10002; 5 int n,m; 6 int tree[maxn]; 7 int x,y,opt; 8 int lowbit(int x) 9 { 10 return x&(-x); 11 } 12 void add(int x,int y) 13 { 14 for(int i=x;i<=10000;i+=lowbit(x)) 15 tree[i]+=y; 16 } 17 int query(int x) 18 { 19 int ans=0; 20 for(int i=x;i>=1;i-=lowbit(i)) 21 ans+=tree[i]; 22 return ans; 23 } 24 int main() 25 { 26 scanf("%d%d",&n,&m);//n个数,m个操作 27 for(int i=1;i<=n;++i) 28 { 29 scanf("%d",&x); 30 add(i,x); 31 } 32 while(m--) 33 { 34 scanf("%d",&opt); 35 if(opt==1) 36 { 37 scanf("%d%d",&x,&y); 38 add(x,y); 39 } 40 else 41 { 42 scanf("%d%d",&x,&y); 43 printf("%d\n",query(y)-query(x-1)); 44 } 45 } 46 return 0; 47 }
用一个差分的思想转变成点修改区间查询。也就是把每一个数和前面的数做一下差,然后把这个新的数组放入树状数组中,这样区间修改就是在l那里加一下 ,在r+1那里减一下,而点查询则变成了查询[1,x]。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int maxn=500005; 5 int n,m; 6 int a[maxn]; 7 int tree[maxn]; 8 int lowbit(int x) 9 { 10 return x&(-x); 11 } 12 void add(int x,int y) 13 { 14 for(int i=x;i<=n;i+=lowbit(i)) 15 tree[i]+=y; 16 } 17 int query(int x) 18 { 19 int ans=0; 20 for(int i=x;i>=1;i-=lowbit(i))ans+=tree[i]; 21 return 0; 22 } 23 int opt,x,y,v; 24 int main() 25 { 26 scanf("%d%d",&n,&m); 27 for(int i=1;i<=n;++i)scanf("%d",&a[i]),a[i]-=a[i-1]; 28 for(int i=1;i<=n;++i)add(i,a[i]); 29 while(m--) 30 { 31 scanf("%d%d",&opt,&x); 32 if(opt==1)//区间修改 33 { 34 scanf("%d%d",&y,&v); 35 add(x,v),add(y+1,-v); 36 }else 37 { 38 printf("%d\n",query(x)); 39 } 40 } 41 return 0; 42 }
树状数组还有很多其他应用,比如cdq的时候用。还有二维树状数组,不过窝太弱了,不会这些qwq
标签:hid isp 树状数组 技术分享 .com onclick 分享 mes while
原文地址:https://www.cnblogs.com/yuelian/p/8757091.html