树状数组
2016-10-12 19:22
197 查看
树状数组网上的解释各种各样,通过昨晚跟今天一下午的努力终于把树状数组基本操作会了。对于树状数组相对于线段树,代码长度小了很多,也没有线段树那么繁琐,但是树状数组可能更难理解一些(我是这么认为的),因为有了二进制的加入,可能很多学习者不想去将十进制变成二进制然后推规律,于是我通过将每个操作进行输出(可以免得让自己推
)进一步加深了对树状数组的理解。
因为我的这篇关于树状数组的博客,是通过同学给的一张图片资料知道如何建树等等的,因此如果您要学习,建议先去百度百科,或者其他大佬的博客先了解一下树状数组基本的知识再来看,这样您就不会看起来一头雾水了。
因为我个人语文能力有限,单纯的像别的博客讲怎么都讲不清,而且,没有代码无法更加形象的讲述。于是我在前面就不对其具体定义进行详细介绍了,直接附上代码。
因为平时做题的习惯,喜欢将代码的每一句的意思都写在旁边,这样,在看代码时也会轻松一些,不用去上面看一眼解释,再看一眼代码了。
下面附上代码,代码旁边都有着详细的解释,只要耐心去看就行了。
欢迎交流学习:QQ:2537267194
下面还给个图片吧,这是我机房一个同学给我的,自己百度没找出来,因此不知道到底出自何方神圣,总之感谢这位大佬!
)进一步加深了对树状数组的理解。
因为我的这篇关于树状数组的博客,是通过同学给的一张图片资料知道如何建树等等的,因此如果您要学习,建议先去百度百科,或者其他大佬的博客先了解一下树状数组基本的知识再来看,这样您就不会看起来一头雾水了。
因为我个人语文能力有限,单纯的像别的博客讲怎么都讲不清,而且,没有代码无法更加形象的讲述。于是我在前面就不对其具体定义进行详细介绍了,直接附上代码。
因为平时做题的习惯,喜欢将代码的每一句的意思都写在旁边,这样,在看代码时也会轻松一些,不用去上面看一眼解释,再看一眼代码了。
下面附上代码,代码旁边都有着详细的解释,只要耐心去看就行了。
//复杂度:单点修改log(n),区间查询log(n) #include<iostream> #include<cstdio> #include<cmath> using namespace std; int n,m,u,v; int a[101],c[101]; inline int lowbit(int i)//lowbit运算,表示2的x次方(x表示i的二进制中从右往左数有连续“0”的个数) { return i&(-i);//-i表示将二进制反转,1变成0,0变成1,最后再在末尾加上1(若最后一位为1就满2进1) } int getsum(int i)//前i个数的和 { int sum=0; while(i>0) { cout<<"i="<<i<<endl; printf("lowbit(%d)=%d\n",i,lowbit(i)); sum+=c[i]; i-=lowbit(i); //当前点减去他的叶子个数就等于c[i]他没有向前包括的点的个数,当他还有没向前包括的点就继续循环 //从上往下寻找 //x-=x&(-x)可得到子节点,不断循环到0则可得到所有的x所有c[x]加起来即为原本前x个元素的和 } return sum; } void Update(int i,int x)//将第i位加上x { while(i<=n) { cout<<"i="<<i<<endl; printf("lowbit(%d)=%d\n",i,lowbit(i)); c[i]+=x; i+=lowbit(i); //主程序中写到 “通过输出lowbit我们不难发现,其实lowbit的值就是当前i的叶子个数 ”也就说明了,当前点的父亲,就等于当前点i加上他的叶子个数 //也就是他的父亲减去他的叶子数就等于他自己 //从下往上更新 //x+=x&(-x)可得到c[x]的所有父亲节点 //通过这个我们也可以得出哪些点与当前点(还有需要更改的点)有存在父亲,爷爷,祖宗的直系亲属关系 } } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++) { int x=i,k=0,y; // while(x%2==0)k++,x/=2; // y=i-pow(2,k)+1; y=i-lowbit(i)+1; printf("lowbit(%d)=%d\n",i,lowbit(i)); //通过输出lowbit我们不难发现,其实lowbit的值就是当前i的叶子个数 cout<<"y="<<y<<endl; cout<<"i="<<i<<endl; for(int j=y;j<=i;j++)c[i]+=a[j]; } for(int i=1;i<=n;i++)cout<<c[i]<<" "; cout<<endl; scanf("%d%d",&u,&v);//把a[u]加上v Update(u,v); scanf("%d",&m);//求前m个数的和 cout<<getsum(m); }因为我只是搞NOIP的,之前学了线段树,因此树状数组就只是稍微涉及了一些基本操作(不涉及二维树状数组),但每一句代码都有解释(有可能也会有误,只是当时个人理解),希望能对您有帮助!
欢迎交流学习:QQ:2537267194
下面还给个图片吧,这是我机房一个同学给我的,自己百度没找出来,因此不知道到底出自何方神圣,总之感谢这位大佬!
相关文章推荐
- 敌兵布阵(杭电1166)(树状数组)
- Codeforces Round #225 (Div. 1) C 树状数组 || 线段树
- HDU 2689 Sort it 求逆序数,树状数组实现
- nyoj 116 士兵杀敌(二)(树状数组)
- hdu5147 (sequence 2) 树状数组
- 树状数组
- poj 3928 树状数组
- 实用数据结构---树状数组(二叉索引树)
- 树状数组
- bzoj 3132: 上帝造题的七分钟 (二维树状数组)
- 1090. In the Army Now (Ural 1090 归并排序||树状数组)
- HDU 2852 KiKi's K-Number 主席树或树状数组
- CSU 1335: 高桥和低桥 (二分查找,树状数组)
- 南阳117求逆序数(离散化+树状数组或归并排序)
- hdu 2838 Cow Sorting 树状数组
- POJ1195:Mobile phones(二维树状数组)
- poj 1990 耳背的牛 两个树状数组
- poj 3928 Ping pong 树状数组
- HDOJ1166 敌兵布阵 树状数组
- hdu 3333 Turing Tree (树状数组+离线处理+离散化)