首页 > 其他分享 >01笔记-树状数组学习笔记

01笔记-树状数组学习笔记

时间:2023-01-01 09:56:09浏览次数:60  
标签:01 树状 int lowbit 笔记 add 数组 op

树状数组学习笔记

树状数组,顾名思义,就是“树状的”数组。树状数组支持以下操作:

  1. 单点修改、区间求和
  2. 区间修改、单点查询
  3. 区间修改、区间查询

这三种操作都是 \(\Theta(logn)\) 的。

树状数组与线段树相比,更好写,但是线段树功能更强大。

树状数组主要依靠 \(lowbit\) ,这是一种求二进制意义下最后一个 \(1\) 的位置的位运算,写起来非常简单:设 \(x\) 为我们要求 \(lowbit\) 的未知数,则 \(lowbit(x)=x\&-x\)

例: \(lowbit(6)=lowbit(0101_2)=0101_2\&1011_2=10_2=2\)

树状数组需要定义一个辅助数组 \({c_i}\),用于存储原数组 \(((a_{i-lowbit(i)+1})+(a_{i-lowbit(i)+2})+...+a_i)\) 的和。
树状数组描述pic-我尽力了

代码1 题目

#include <iostream>
using namespace std;
int n, m;
// int a[100010];
int C[500010];
#define lowbit(x) x & (-x)
void add(int x, int k)//给位置 x 加上 k,这里是递增加的(即从这棵‘树’的叶子结点往上加的)
{
    while (x <= n){
        C[x] += k;
        x += lowbit(x);
}
}
int getsum(int x)//获取从1到x的元素和,这里是递减加的
{
    int res = 0;
    while (x){
        res += C[x];
        x -= lowbit(x);
    }
    return res;
}
int main()
{
    ios::sync_with_stdio(false);
    cin >> n >> m;
    int t;
    for (int i = 1; i <= n; i++){
        cin >> t;
        add(i, t);
    }
    for (int i = 1; i <= m; i++){
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 1){
            add(x, y);
        }
        else{
            cout << getsum(y) - getsum(x - 1) << endl;
        }
    }
    return 0;
}

对于2,我们考虑差分(注:差分是前缀和的逆运算,比如我想要给数组 \(a\) 的 \([l,r]\) 中加上 \(k\) ,我们就可以定义一个新数组 \(s\) , 把 \(s_l+k,s_{r+1}-k\), 此时我们 $a_m=a_m+\sum_{i=0}^{m} s_i $)。我们要优化的就是这个求和的过程。

我们首先把 \(c\) 数组全部初始化为 \(0\),然后在每次区间 \([l,r]\) 加上 \(x\),就把 \(c_l+x , c_{r+1}-x\) , 在查询时查找 \(c_1+c_2+... + c_x\) 的和就可以了。

代码2 题目

#include <iostream>
#include <cstdio>
using namespace std;
int n,m;
int C[500010],a[500010];
inline int lowbit(int x){
    return x&(-x);
}
void add(int x,int k){
    while(x<=n){
        C[x]+=k;
        x+=lowbit(x);
    }
}
int getsum(int x){
    int res=0;
    while(x){
        res+=C[x];
        x-=lowbit(x);
    }
    return res;
}
int main() {
    ios::sync_with_stdio(false);
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<=m;i++){
        int op;
        cin>>op;
        if(op==1){
            int x,y,k;
            cin>>x>>y>>k;
            add(x,k);//差分
            add(y+1,-k);//差分
        }
        else{
            int x;
            cin>>x;
            cout<<a[x]+getsum(x)<<endl;
        }
    }
    return 0;
}

对于3,这里我引用了一位大佬@胡小兔 的说明:
img

代码 题目:

//这里我为了方便
//把1号的+-都认为是进行了一个[1,1]的区间修改
#include<iostream>
using namespace std;
#define lowbit(x) x&(-x)
long long c1[200010],c2[200010],a[200010];
long long n, f;
void add(long long y, long long k)
{
    int x=y;
    while(x<=n){
        c1[x]+=k;
        c2[x]+=k*y;
        x+=lowbit(x);
    }
}
long long getsum(long long y)
{
    long long res = 0;
    long long x = y;
    while(x){
        res+=(y+1)*c1[x]-c2[x];
        x-=lowbit(x);
    }
    return res;
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>f;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        add(i, a[i]);
        add(i+1, -a[i]);
    }
    for(int i=1;i<=f;i++){
        long long op, l, r, k;
        cin>>op;
        if(op==1){
            cin>>l>>r>>k;
            add(l,k);
            add(r+1,-k);
        }
        else if(op==2){
            cin>>k;
            add(1,k);
            add(2,-k);
        }
        else if(op==3){
            cin>>k;
            add(1,-k);
            add(2,k);
        }
        else if(op==4){
            cin>>l>>r;
            cout<<getsum(r)-getsum(l-1)<<endl;
        }
        else if(op==5){
            cout<<getsum(1)<<endl;
        }
    }
    return 0;
}

标签:01,树状,int,lowbit,笔记,add,数组,op
From: https://www.cnblogs.com/wang-yishan/p/17017722.html

相关文章

  • Android笔记--文本输入
    编辑框EditText相关内部部件取下:inputType的类型如下:具体实现:不同边框的实现:焦点变更监听器具体实现:文本变化监听器具体实现:......
  • 二分学习笔记
    写在前面:本文中的“单调”不包括“单调不变”。(我不说你们应该也不会想到)一、算法引入如果我们要用一个数列(各个位置要有相应的数字形式的下标,且我们的这个下标可为小数......
  • sql server 2012 导出SQL文件
    一.工具1.1sqlserver2012二.方法2.1打开sqlserver2012,连接成功后,选择需要导出表的数据库--任务---生成脚本2.2显示:生成和发布脚......
  • CS:APP--Chapter01 : A tour of computer systems
    CS:APP--Chapter01:Atourofcomputersystems标签(空格分隔):CS:APP目录CS:APP--Chapter01:Atourofcomputersystems1.1InformationIsBits+Context[chapt......
  • buuctf-web-[极客大挑战 2019]PHP 1
    知识点:文件备份、反序列化打开网站后发现源码没有提示,页面提示“备份的好习惯”,用御剑扫后台,扫出www.zip,打开发现有几个php文件打开index.php发现关键代码<?phpin......
  • riscv学习笔记
    Riscv是现在比较火的一套开源指令集(ISA),这就有很多搞头了,可定制化,不用收费,不像arm虽然很成熟,但是需要几百到几千万不等的授权费,对于小公司来说成本过于高昂。Sifive是Riscv......
  • .NET 云原生架构师训练营(基于 OP Storming 和 Actor 的大型分布式架构二)--学习笔记
    目录为什么我们用OrleansDaprVSOrleansActor模型Orleans的核心概念结合OPStorming的实践结合OPStorming的实践业务模型设计模型代码实现业务模型我们可以把关键......
  • 学习笔记282—SD与SEM有区别吗
    SD是标准偏差,反映的是样本变量值的离散程度。SEM是标准误差,反映的是样本均数之间的变异。SD为样本标准差,根据标准差SD能反映变量值的离散程度。正负值就是在计算好的SD上......
  • day41_0501.二叉搜索树中的众数
    我的思路递归法如果是二叉搜索树如果不是二叉搜索树迭代法我的思路classSolution{private:unordered_map<int,int>map;vector<int>res......
  • Sumitomo Mitsui Trust Bank Programming Contest 2019 —— B
    也不知道这比赛为啥要取这么长的名称(传送门:https://atcoder.jp/contests/sumitrust2019/tasks/sumitb2019_e哈哈,你被骗了!但网址是真的!题意有红绿蓝三种帽子RedandBl......