树状数组
|
? 处理何种问题:常用于动态更新情况下的求区间和,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;
}
(编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |

