一维树状数组~
来源:互联网 发布:linux退出不保存文件 编辑:程序博客网 时间:2024/05/13 01:19
树状数组按照一定的规律来存储原数组的一些区间的和,以此可将查询和修改的复杂度都优化到O(logn),规律如下:
从表面上看,树状数组C[i](1<=i<=n)中,当i为奇数的时候C[i]存的是A[i];当i为偶数时,如果i能表示为2的次幂则C[i]=A[1]+A[2]+···+A[i],如果i不能表示为2的次幂则C[i]=A[i-1]+A[i]。但还有更深层次的规律,其实C[i]=A[i-k+1]+A[i-k+2]+···+A[i](1<=i<=n);k=1<<x,x是i的二进制表示下右边0的个数,即
int lowbit(int i){ return i&(-i);}lowbit()函数的返回值就是k。例如,当i=5时,int类型,4字节,占32位:
5的二进制为: 00000000 00000000 00000000 00000101
5的反码为: 11111111 11111111 11111111 11111010
-5的二进制为:11111111 11111111 11111111 11111011
lowbit(5)=1;所以,C[5]=A[5];
PS:
在计算机中,负数以其正值的补码形式表达。
反码表示法规定:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。
补码表示法规定:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1。
例题:NYOJ_士兵杀敌(二)
题意:插点问线
思路:向后修改,向前求和
CODE:
/****author :Or_me **╭︿︿︿╮{/ a c /} ( (oo) ) ︶︶︶ ** ****NYOJ_116题**** 2014 年 7月 31日****/#include <set>#include <map>#include <cmath>#include <queue>#include <stack>#include <vector>#include <cstdio>#include <string>#include <cctype>#include <climits>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;const int MAX=1000001;int c[MAX];int N,M;int lowbit(int t)//lowbit(0)=0,会形成死循环,所以数组下标从1开始{ return t&-t;}void Modify(int m,int n)//向后修改{ for (int k=m; k<=N; k+=lowbit(k)) c[k]+=n;}int sum(int x)//向前求和{ int ans=0; for (int i=x; i>=1; i-=lowbit(i)) ans+=c[i]; return ans;}int getsum(int i,int j){ return sum(j)-sum(i-1);}int main(){ int m,n,v; char ch[7]; scanf("%d%d",&N,&M); for (int i=1; i<=N; i++) { scanf("%d",&v); Modify(i,v); } for (int i=1; i<=M; i++) { scanf("%s%d%d",ch,&m,&n); if (ch[0]=='A') Modify(m,n); else if (ch[0]=='Q') printf("%d\n",getsum(m,n)); } return 0;}
例题:NYOJ_士兵杀敌(四)
题意:插线问点
思路:向前修改,向后求和
CODE:
/****author :Or_me **╭︿︿︿╮{/ a c /} ( (oo) ) ︶︶︶ ** **** 题**** 2014 年 月 日****/#include <set>#include <map>#include <cmath>#include <queue>#include <stack>#include <vector>#include <cstdio>#include <string>#include <cctype>#include <climits>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;const int MAX=1000001;int c[MAX];int N,M,T;int lowbit(int t){ return t&-t;}void Modify(int m,int n)//向前修改{ for (int k=m; k>0; k-=lowbit(k)) c[k]+=n;}int sum(int x)//向后求和{ int ans=0; for (int i=x; i<=M; i+=lowbit(i)) ans+=c[i]; return ans;}int main(){ int a,b,t,x; char ch[7]; memset(c,0,sizeof(c)); scanf("%d%d",&T,&M); for (int i=1; i<=T; i++) { scanf("%s",ch); if (ch[0]=='A') { scanf("%d%d%d",&a,&b,&t); Modify(a-1,-t); Modify(b,t); } else { scanf("%d",&x); printf("%d\n",sum(x)); } } return 0;}例题:NYOJ_士兵杀敌(五)
题意:插线问线
思路:树状数组离线版,查询在修改之后
CODE:
/****author :Or_me **╭︿︿︿╮{/ a c /} ( (oo) ) ︶︶︶ ** **** 题**** 2014 年 月 日****/#include <set>#include <map>#include <cmath>#include <queue>#include <stack>#include <vector>#include <cstdio>#include <string>#include <cctype>#include <climits>#include <cstring>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;const int MAX=1000001;int c[MAX];int main(){ int N,C,Q; int a,b,x; scanf("%d%d%d",&N,&C,&Q); while (C--) { scanf("%d%d%d",&a,&b,&x); c[a]+=x; c[b+1]-=x; } for (int i=1;i<=N;i++)//得到每个士兵的战功 { c[i]=c[i-1]+c[i]; } for (int i=1;i<=N;i++)//得到前缀和 { c[i]=(c[i-1]+c[i])%10003;//保存的是余数 } while (Q--) { scanf("%d%d",&a,&b); printf("%d\n",(c[b]-c[a-1]+10003)%10003);//+10003,防止结果小于0 } return 0;}
0 0
- 一维树状数组
- 一维树状数组
- 一维树状数组~
- 一维树状数组
- 一维树状数组
- 一维 二维树状数组
- 一维树状数组小结
- 一维树状数组模板
- 树状数组,一维,二维
- 一维的树状数组
- 《一维树状数组》模板
- 一维树状数组入门
- 一维树状数组BIT
- 树状数组--一维模板
- 树状数组(一维)
- 【树状数组】树状数组一维二维模板
- 一维树状数组和二维树状数组
- Stars 【一维树状数组-典型例题】
- hdoj 1999 不可模数
- [ACM] hdu 4405 Aeroplane chess (概率DP)
- 二分匹配 最大的匹配数 (简单)
- 在Android开发中,定时执行任务的3种实现方法:
- jboss5.1集群安装
- 一维树状数组~
- 巧用vs2012"对解决方案运行代码分析"功能(Alt+F11),揪出Ninject-IOC容器重大隐患!
- 一体化红外接收头有两种
- Oracle-11G-DataGuard 一主库多备库详细配置
- Android onTouchEvent, onClick及onLongClick的调用
- 使用jQuery能做什么?
- 二分匹配的 基本信息的解释
- java导出excel不需要额外jar包
- Julia:last() 和first()