树状数组
? 处理何种问题:常用于动态更新情况下的求区间和,LIS里的求最大值也用到了树状数组。 ? 时间复杂度:单次更新和求和的时间复杂度都是O(logn) ? 原理:lowbit()函数是整个树状数组的核心,但是在这里我就不说他的理论基础了,只说一下它的功能,例如:给一个原始数组A[]:1,2,3,4,5,6,7,8,9; 被加工之后就是树状数组C[]:1,3,3,10,5,11,7,36,9;即 C1 = A1 C2 = A1+A2 C3 = A3 C4 = A1+A2+A3+A4 C5 = A5 C6 = A5+A6 C7 = A7 C8 = A1+A2+A3+A4+A5+A6+A7+A8 C9 = A9 如下图所示: ? 树状数组并不是一个二叉树(不像线段树),对于每一个节点,例如C6,我们需要求的是它的父亲节点和前面一个相邻的兄弟节点是哪一个,这些用lowbit()函数都是可以很快捷的找到,即C6的前一个兄弟节点是6-lowbit(6),而他的父亲节点是6+lowbit(6)。 利用如此操作之后,在动态查询修改之后我们不必对全局进行全部修改,只需要更改节点值就可以了,在log级的时间内完成查询和修改。 lowbit(x)=(x&(-x)); ? 实现步骤:具体看代码,略 ? 备注:略 ? 输入样例解释: 10? //数组元素个数 1 2 3 4 5 6 7 8 9 10 2 1 3? // 2代表查询区间[1,3]之和 1 3 6? // 1代表给第3个元素加上6 2 2 7 1 10 -2 1 6 3 2 3 10 ? 输出样例解释: 6 //查询结果 33 59 //对于树状数组,有利有弊,代码也是的确简单,常用在动态更新求区间和 //当然,某些情况下的求解最大值也是可以做的,代码也的确比线段树好写的多 //单点更新的操作可以利用Sum找出单点值,再用Add更新两次即可 #include<iostream> #include<cstdio> #include<string.h> #include<algorithm> using namespace std; #define lowbit(x) (x&(-x)) const int MaxN=10001000; long long arr[MaxN]; int n; void Build() { memset(arr,sizeof(arr)); long long temp; int j; for(int i=1; i<=n; ++i) { scanf("%lld",&temp); j=i; while(j<=n) { arr[j]+=temp; j+=lowbit(j); } } } void Add(int x,int val) { while(x<=n) { arr[x]+=val; x+=lowbit(x); } } long long sum(int x) { long long ans=0; while(x>0) { ans+=arr[x]; x-=lowbit(x); } return ans; } int main() { int temp,take; while(~scanf("%d",&n)) { Build();//建树 while(scanf("%d",&take)) { if(take==1)//单点添加 { int x,val; scanf("%d%d",&x,&val); Add(x,val); } else//求区间和 { int l,r; scanf("%d%d",&l,&r); printf("%lldn",sum(r)-sum(l-1)); } } } return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |