【树状数组(一)】
来源:互联网 发布:地方门户cms 编辑:程序博客网 时间:2024/06/05 20:40
树状数组,又称二进制索引树,英文名Binary Indexed Tree。
一、树状数组的用途
主要用来求解数列的前缀和,a[0]+a[1]+...+a[n]。
由此引申出三类比较常见问题:
1、单点更新,区间求值。(HDU1166)
2、区间更新,单点求值。(HDU1556)
3、求逆序对。(HDU2838)
二、树状数组的表示
1、公式表示
设A[]为一个已知的数列。C[]为树状数组。则会有
C[i]=A[j]+...+A[i];j=i&(-i)=i&(i^(i-1))。
2、图形表示
(注:1、最下面的一行表示数组A,上面的二进制表示的部分是C;
从以上可以发现:
1、树状数组C是表示普通数组A的一部分的和。
2、小标为奇数时,C[i]只能管辖一个A[i]。
3、C[i]的最后一个数一定是A[i]。
一维树状数组常用的3个函数
int lowbit(int x) //取x的最低位1,比如4,则返回4,如5,则返回1{return x&(-x);}void update(int i, int val) //将第i个元素增加val{//i的祖先都要增加valwhile(i <= n){sum[i] += val;i += lowbit(i); //将i的二进制未位补为得到其祖先}}int Sum(int i) //求前i项的和{int s = 0;//将前i项分段while(i > 0){s += sum[i];i -= lowbit(i); //去掉i的二进制最后一个}return s;}
/*HDU 1166单点更新,区间求值*/#include<cstdio>#include<cstring>#include<iostream>using namespace std;const int maxn=50001;int a[maxn],c[maxn];int n;int lowbit(int t){ //取x的最低位1,比如4,则返回4,如5,则返回1 return t&(-t);}void modify(int t,int num){ //将第t个元素增加val while(t<=n){ c[t]+=num; t+=lowbit(t); //将t的二进制未位补为得到其祖先 }}int getresult(int t){ //求前t项的和 int sum=0; while(t>0){ sum+=c[t]; t-=lowbit(t); //去掉t的二进制最后一个 } return sum;}void init(){ for(int i=1;i<=n;i++){ scanf("%d",&a[i]); modify(i,a[i]); }}int main(){ int test,k=1; scanf("%d",&test); while(test--){ memset(c,0,sizeof(c)); printf("Case %d:\n",k++); scanf("%d",&n); init(); char ch[15]; int a,b; while(scanf("%s",&ch),strcmp(ch,"End")){ scanf("%d%d",&a,&b); switch(ch[0]){ case 'Q': printf("%d\n",getresult(b)-getresult(a-1)); break; case 'A': modify(a,b); break; case 'S': modify(a,-b); break; } } }}
/*HDU1556区间更新,单点求值*/#include<cstdio>#include<cstring>using namespace std;int c[100005]; int n;int lowbit(int x){ return x&(-x);}void updata(int i,int num){ while(i<=n){ c[i]+=num; i+=lowbit(i); }}int getsum(int i){ int sum=0; while(i>0){ sum+=c[i]; i-=lowbit(i); } return sum;}int main(){ int a,b; while(scanf("%d",&n),n){ memset(c,0,sizeof(c)); for(int i=1;i<=n;i++){ scanf("%d%d",&a,&b); updata(a,1);//大于a的点都加1 updata(b+1,-1);//然后把大于b+1的点都减一 } //得到的就是a到b都加1. for(int j=1;j<n;j++) printf("%d ",getsum(j)); printf("%d\n",getsum(n)); }}
/*题意:给你N个排列不规则的数,任务是把它从小到大排好,每次只能交换相邻两个数,交换一次的代价为两数之和,求最小代价思路:求解比a小的个数然后求解比a小的个数的总和然后所有数的和,*/#include<iostream>#include<cstring>using namespace std;const int maxn=100001;struct node{ int cnt; long long sum;}tree[maxn];int n;int lowbit(int x){ return x&(-x);}void modify(int x,int y,int t){ while(x<=n){ tree[x].sum+=y; tree[x].cnt+=t; //tree[].cnt来保存a出现的次数 x+=lowbit(x); }}long long query_cnt(int x){ //比x小的数的个数 long long sum=0; while(x>0){ sum+=tree[x].cnt; x-=lowbit(x); } return sum;}long long query_sum(int x){ //比x小的所有数之和 long long sum=0; while(x>0){ sum+=tree[x].sum; x-=lowbit(x); } return sum;}int main(){ while(cin>>n){ int a; long long ans=0; memset(tree,0,sizeof(tree)); for(int i=1;i<=n;i++){ cin>>a; modify(a,a,1); //以a为下标更新数组 long long k1=i-query_cnt(a); //k1为前i个数比a大的数的个数 if(k1!=0){ long long k2=query_sum(n)-query_sum(a); //目前所有数的和-目前所有比a小的数的和,为比a大的数的和 ans+=k1*a+k2; //调换a所需的时间 } } cout<<ans<<endl; }}
http://blog.csdn.net/maiyuetong/article/details/6661496
http://blog.csdn.net/lulipeng_cpp/article/details/7816527
http://hawstein.com/posts/binary-indexed-trees.html
http://blog.csdn.net/zxy_snow/article/details/6264135
0 0
- 【树状数组(一)】
- 【树状数组(一)】
- 树状数组(一)
- 树状数组(一)
- 树状数组(一)
- 树状数组(一)
- 树状数组(一维)
- hdu4000(一维树状数组模板)
- ACM斩草除根系列(一) 树状数组
- 树状数组题目总结(一)
- 树状数组(一维、二维)入门
- NYOJ108 士兵杀敌(一)【树状数组】
- 树状数组学习(一维)
- 树状数组模板(一维的)
- 树状数组(一维&&二维)
- NSWOJ1204 士兵杀敌(一)(树状数组)
- 【模板篇】树状数组们(一)
- 一维树状数组
- 缩略图导航画廊jQuery代码
- 人工客服,二维码折扣,粉丝行为分析等源码分享
- crontab用法
- 不惧刀片 机架式和塔式服务器依旧强势(1) - 51CTO.COM
- LBP matlab code
- 【树状数组(一)】
- Excel vba中使用vlookup函数
- Facebook中国招聘:研发运营中心有望先行
- shell perl tcl python 和rubby
- Python 随笔1
- 【Android学习笔记】如何添加管理Menu
- jdk环境变量配置
- windows7 旗舰版 不能将程序锁定到任务栏
- 黑马程序员_学习笔记:15) 网络编程:Socket(udp、tcp)