您的位置:首页 > 其它

UVA12086 树状数组 + 裸 +单点重置

2016-05-07 20:21 423 查看
0)

树状数组与线段树都适用于在一个连续数列中任意指定两个数求这两个数之间所有数之和的情景。

而传统数组(共n个元素)的元素修改和连续元素求和的复杂度分别为O(1)和O(n),树状数组主要利用二分的思想构造伪树的结构,使修改和求和的时间复杂度

均为O(logn),(线性结构只能逐个扫描元素,而树状结构可以实现跳跃式扫描)提高了效率。

相对于容易理解但所占内存空间偏大的线段树而言(线段树的节点数,一般是题目中点的个数的3或4倍),树状数组所占内存空间较小(该结构中节点数一般比题目中点的个数稍大一点即可)。

本质 树状数组,对于其中某些节点(不是全部)的值,是其下辖的另一些节点之和,所以对于任意区间区间求和时,不用将该区间内所有点都加一遍,只要加几个节点值即可。

自己的理解还不深刻,只是到了能用的地步,网上的一些博客已经归纳的不错了,便不再赘述。

参考博客:董的博客(有一些小错误)点击打开链接;用二进制的角度来看易于加深理解点击打开链接 等等。

1)

#include <iostream>
#include <stdio.h>
#include <string.h>

using namespace std;
const int maxn=200010;
int star[maxn];//就是每一个potmeters结点
int a[maxn];
//int level[maxn];
int Init(int x){
return x&(-x);//2^k,k是x以二进制形式时末尾0的个数;2^k==x&(x^(x-1))==<span style="text-indent: 25.2px; font-family: Arial, Helvetica, sans-serif;">x&(-x)</span>
}
int Sum(int x){
int res=0;
while(x>0){
res+=star[x];
x-=Init(x);
}
return res;
}
void Add(int i,int pos,int value){
while(pos<=maxn){
star[pos]=star[pos]-a[i]+value;
pos+=Init(pos);
}
return ;
}
int main()
{
int n;
int kase=0;
while(~scanf("%d",&n)){
if(n==0){
break;
}
if(kase!=0){
cout<<endl;
}
kase++;
memset(star,0,sizeof(star));
memset(a,0,sizeof(a));
//memset(level,0,sizeof(level));
for(int i=1;i<=n;i++){
int temp;
scanf("%d",&temp);
Add(i,i,temp);
a[i]=temp;
}
string com;
printf("Case %d:\n",kase);
while(cin>>com&&com!="END"){
int x;
int y;
scanf("%d%d",&x,&y);
//增加Add和求和Sum完全是不同的两条路径
if(com=="M"){
cout<<Sum(y)-Sum(x-1)<<endl;
}
else if(com=="S"){
Add(x,x,y);
a[x]=y;
}

}
}
return 0;
}


2)
UVA12086
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: