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

本文介绍树状数组和线段树这两种数据结构,在连续数列中进行元素修改和区间求和操作的应用。通过对比两种结构的特点,重点介绍了树状数组的实现原理及其优势,包括较低的空间占用和高效的查询及更新复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值