算法和数据结构--树状数组

概念:

树状数组的初衷是解决状态压缩空间里的累积频率,现在多用于求前缀和与后缀和(方便计算),它可以以 O(logN)的时间得到任意前缀和,并同时支持在 O(logN)时间内支持动态单点值的修改。空间复杂度 O(N)。

树状数组的引用:

树状数组最重要的作用便是修改与查询,分为单点修改区间查询区间修改单点查询区间修改区间查询。

关于修改(即add,维护数组)的想法:我们一般是挨个维护数组,而树状数组用区间来维护,当我们修改单点时,我们只需修改包含该点的元素,即其父节点!求区间和时也只需将每个区间的父节点相加即可(一个父节点包括一个区间的数),求区间和时只需S[1,B]-S[1,A-1]即可。

 

 修改时候可以发现是个“爬树”的过程,一路往上更新,直到MAX(树状数组最大容量)!

 

 

 树状数组的实现:

前面已经讲得很详细了,代码实现倒是一件简单的事了。不过我们需要先解决一个问题:lowbit怎么算?如果一位一位验证的话,会形成额外的时间开销。然而,我们有这样神奇的一个公式:

low(x)=(x)&(−x)

为什么可以这样?我们需要知道,计算机里有符号数一般是以补码的形式存储的。-x相当于x按位取反再加1,会把结尾处原来1000...的形式,变成0111...,再变成1000...;而前面每一位都与原来相反。这时我们再把它和x按位与,得到的结果便是lowbit(x)。

这样就能愉快的写出树状数组(模板)啦:

单点修改and区间查询:

初始化的时候,我们只需要cnt[i]每个点的初始值即可。

//修改
ll add(ll x,ll y)
{
    for(ll i=x;i<=n;i+=lowbit(i))
    {
        cnt[i]+=y;
    }
}
//求前n项和
ll query(ll x)
{
    ll sum=0;
    for(ll i=x;i;i-=lowbit(i)
    {
        sum+=cnt[i];
    }
    return aum;
}
//求区间和
return query(B)-query(A-1);

 模板[1]:

//单点修改,区间查询
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
vector<ll>a(5e5+5),b(5e5+5);
ll n,k;
ll lowbit(ll x)
{
	return x&(-x);
}
void add(ll x,ll y)
{
	for(ll i=x;i<=n;i+=lowbit(i))
	{
		b[i]+=y;
	}
}
void query(ll x,ll y)//前缀和相减求区间和
{
	ll sum=0;
	for(ll i=x-1;i;i-=lowbit(i))
	{
		sum-=b[i];
	}
	for(ll i=y;i;i-=lowbit(i))
	{
		sum+=b[i];
	}
	cout<<sum<<'\n';
}
void solve()
{
	cin>>n>>k;
	for(ll i=1;i<=n;i++)
	{
		cin>>a[i];
		add(i,a[i]);//该节点与父节点及右侧2的幂的点都加上该数,利于求区间和
	}
	ll t,x,y;
	while(k--)
	{
		cin>>t>>x>>y;
		if(t==1)
		{
			add(x,y);//同理
		}
		else{
			query(x,y);//前缀和差
			//cout<<query(x,y)<<'\n';
		}
	}
}
int main()
{
	//ll t;cin>>t;
	//while(t--) 
		solve();
}

区间修改and单点查询: 

此时我们需要的是差分数组,查询单点的时候,只需求该点的前n项和即可(差分数组的前n项和即原数组在该点的值)。

模板[2]:

//区间修改,查询单点
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
ll n,m;
ll c[500005],a[500005];
ll lowbit(ll x)
{
	return x&(-x);
}
void add(ll x,ll z)
{
	for(ll i=x;i<=n;i+=lowbit(i))
	{
		c[i]+=z;
	}
}
ll query(ll x)
{
	ll sum=0;
	for(ll i=x;i;i-=lowbit(i))//差分前缀和
	{
		sum+=c[i];
	}
	return sum;
}
void solve()
{
	cin>>n>>m;
	for(ll i=1;i<=n;i++)
	{
		cin>>a[i];
		add(i,a[i]-a[i-1]);//差分数组
	}
	ll t,x,y,z;
	while(m--)
	{
		cin>>t;
		if(t==1)
		{
			cin>>x>>y>>z;
			add(x,z);//原本差分数组只用修改一次,但是其含有多级父节点,故需要多次修改
			add(y+1,-z);
		}
		else{
			cin>>x;
			cout<<query(x)<<'\n';//差分前缀和
		}
	}
}
int main()
{
	//ll t;cin>>t;
	//while(t--) 
	solve();
	return 0;
}

 区间修改and区间查询:

咱们知道a[n]等于差分数组前n项和,如果求一个区间的话,便是这个区间每个数的前n项和。

硬算肯定TLE,手推可得:

核心公式:

n *(c[1]+c[2]+……+c[n])-(0 *c[1]+1 *c[2]+...+(n-1)*c[n])

模板[3]:

// ****n *(c[1]+c[2]+……+c[n])-(0 *c[1]+1 *c[2]+...+(n-1)*c[n])***** 
//区间修改,区间查询
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
ll n,m;
ll c[100005],a[100005],b[100005];
ll lowbit(ll x)
{
	return x&(-x);
}
///
void add(ll x,ll z)
{
	for(ll i=x;i<=n;i+=lowbit(i))
	{
		c[i]+=z;
	}
}
///
void added(ll x,ll z)
{
	for(ll i=x;i<=n;i+=lowbit(i))
	{
		b[i]+=z;
	}
}
/
ll query(ll x)
{
	ll sum=0;
	for(ll i=x;i;i-=lowbit(i))
	{
		sum+=c[i];
	}
	return sum;
}
/
ll queryed(ll x)
{
	ll sum=0;
	for(ll i=x;i;i-=lowbit(i))
	{
		sum+=b[i];
	}
	return sum;
}
/
void solve()
{
	cin>>n>>m;
	for(ll i=1;i<=n;i++)
	{
		cin>>a[i];
		add(i,a[i]-a[i-1]);//差分数组
		added(i,(i-1)*(a[i]-a[i-1]));//待减差分数组,即:(0 *c[1]+1 *c[2]+...+(n-1)*c[n]);
	}
	ll t,x,y,z;
	while(m--)
	{
		cin>>t;
		if(t==1)
		{
			cin>>x>>y>>z;
			add(x,z);//多级父节点,故需要多次修改,为了使用前缀和
			add(y+1,-z);
			added(x,z*(x-1));
			//同理:即 (0 *c[1]+1 *c[2]+...+(n-1)*c[n]);
			added(y+1,-z*(y));
		}
		else{
			cin>>x>>y;
			ll sum1=0,sum2=0;
			sum1=(x-1)*query(x-1)-queryed(x-1);//a[x-1]的前缀和
			sum2=y*query(y)-queryed(y);//a[y]的前缀和
			//即:*****n *(c[1]+c[2]+……+c[n])-(0 *c[1]+1 *c[2]+...+(n-1)*c[n])*****
			cout<<sum2-sum1<<'\n';
		}
	}
}
int main()
{
	//ll t;cin>>t;
	//while(t--) 
	solve();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/329745.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何根据自己的数据集微调一个 Transformer 模型

将通过 NLP 中最常见的文本分类任务来学习如何在自己的数据集上利用迁移学习&#xff08;transfer learning&#xff09;微调一个预训练的 Transformer 模型—— DistilBERT。DistilBERT 是 BERT 的一个衍生版本&#xff0c;它的优点在它的性能与 BERT 相当&#xff0c;但是体积…

Unity3d C#实现场景编辑/运行模式下3D模型XYZ轴混合一键排序功能(含源码工程)

前言 在部分场景搭建中需要整齐摆放一些物品&#xff08;如仓库中的货堆、货架等&#xff09;&#xff0c;因为有交互的操作在单个模型上&#xff0c;每次总是手动拖动模型操作起来也是繁琐和劳累。 在这背景下&#xff0c;我编写了一个在运行或者编辑状态下都可以进行一键排序…

【嘉立创EDA-PCB设计指南】3.网络表概念解读+板框绘制

前言&#xff1a;本文对网络表概念解读板框绘制&#xff08;确定PCB板子轮廓&#xff09; 网络表概念解读 在本专栏的上一篇文章【嘉立创EDA-PCB设计指南】2&#xff0c;将设计的原理图转为了PCB&#xff0c;在PCB界面下出现了所有的封装&#xff0c;以及所有的飞线属性&…

从0开始python学习-48.pytest框架之断言

目录 1. 响应进行断言 1.1 在yaml用例中写入断言内容 1.2 封装断言方法 1.3 在执行流程中加入断言判断内容 2. 数据库数据断言 2.1 在yaml用例中写入断言内容 2.2 连接数据库并封装执行sql的方法 2.3 封装后校验方法是否可执行 2.4 使用之前封装的断言方法&#xff0c…

austin-admin 消息推送平台前端项目依赖低代码平台Amis 怎么使用

austin-admin 消息推送平台前端项目&#x1f525;依赖低代码平台Amis 怎么使用 收到一个通知&#xff0c;要将部署一个开源的消息系统 :austin的前端开源&#xff1a;https://gitee.com/zhongfucheng/austin-admin 本地运行 1、使用npm或者yarn这些咯 yarn yarn start2、使用…

【LabVIEW FPGA入门】FPGA中的数学运算

数值控件选板上的大部分数学函数都支持整数或定点数据类型&#xff0c;但是需要请注意&#xff0c;避免使用乘法、除法、倒数、平方根等函数&#xff0c;此类函数比较占用FPGA资源&#xff0c;且如果使用的是定点数据或单精度浮点数据仅适用于FPGA终端。 1.整数运算 支持的数…

pyechart基础

pyecharts - A Python Echarts Plotting Library built with love. 全局配置项 初识全局配置组件 Note: 配置项章节应该配合图表类型章节中的 example 阅读。 全局配置项可通过 set_global_opts 方法设置 InitOpts&#xff1a;初始化配置项 class pyecharts.options.InitO…

Java顺序表(2)

&#x1f435;本篇文章将对ArrayList类进行讲解 一、ArrayList类介绍 上篇文章我们对顺序表的增删查改等方法进行了模拟实现&#xff0c;实际上Java提供了ArrayList类&#xff0c;而在这个类中就包含了顺序表的一系列方法&#xff0c;这样在用顺序表解决问题时就不用每次都去实…

【C++干货铺】红黑树 (Red Black Tree)

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 前言 红黑树的概念 红黑树的性质 红黑树结点的定义 红黑树的插入操作 插入新的结点 检查规则进行改色 情况一 情况二 情况三 插入完整代码 红黑树的验…

SpringMVC参数接收见解4

# 4.参数接收Springmvc中&#xff0c;接收页面提交的数据是通过方法形参来接收&#xff1a; 处理器适配器调用springmvc使用反射将前端提交的参数传递给controller方法的形参 springmvc接收的参数都是String类型&#xff0c;所以spirngmvc提供了很多converter&#xff08;转换…

【数据结构】归并排序的两种实现方式与计数排序

前言&#xff1a;在前面我们讲了各种常见的排序&#xff0c;今天我们就来对排序部分收个尾&#xff0c;再来对归并排序通过递归和非递归的方法进行实现&#xff0c;与对计数排序进行简单的学习。 &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; 专栏…

Android Matrix绘制PaintDrawable设置BitmapShader,手指触点为圆心scale放大原图,Kotlin

Android Matrix绘制PaintDrawable设置BitmapShader&#xff0c;手指触点为圆心scale放大原图&#xff0c;Kotlin 在 Android基于Matrix绘制PaintDrawable设置BitmapShader&#xff0c;以手指触点为中心显示原图的圆切图&#xff0c;Kotlin&#xff08;4&#xff09;-CSDN博客 的…

2001-2022年上市公司企业财务绩效、公司价值、并购绩效数据(ROA、ROE、TOBINQ变化)

2001-2022年上市公司企业财务绩效、公司价值、并购绩效数据&#xff08;ROA、ROE、TOBINQ变化&#xff09; 1、时间&#xff1a;2001-2022年 2、指标&#xff1a;证券代码、统计截止日期、证券简称、行业代码、行业名称、年份、、总资产净利润率B、净资产收益率(ROE)B、托宾Q…

【方法】如何压缩zip格式文件?

zip是一种常见的压缩文件格式&#xff0c;能够高效打包文件便于存储和传输&#xff0c;那zip格式的压缩文件要如何压缩呢&#xff1f; 压缩zip文件需要用到解压缩软件&#xff0c;比如常见的WinRAR、7-Zip软件都可以压缩zip格式。下面一起来看看具体如何操作。 一、使用WinRAR…

日期处理第一篇--优雅好用的Java日期工具类Joda-Time

日常开发中&#xff0c;处理时间和日期是很常见的需求。基础的java内置工具类只有Date和Calendar&#xff0c;但是这些工具类的api使用并不是很方便和强大&#xff0c;于是就诞生了Joda-Time这个专门处理日期时间的库。 简介 Joda-Time提供了Java日期处理的优雅的替代品&…

IntelliJ IDEA 拉取gitlab项目

一、准备好Gitlab服务器及项目 http://192.168.31.104/root/com.saas.swaggerdemogit 二、打开 IntelliJ IDEA安装插件 打开GitLab上的项目&#xff0c;输入项目地址 http://192.168.31.104/root/com.saas.swaggerdemogit 弹出输入登录用户名密码&#xff0c;完成。 操作Comm…

【昕宝爸爸小模块】图文源码详解什么是线程池、线程池的底层到底是如何实现的

➡️博客首页 https://blog.csdn.net/Java_Yangxiaoyuan 欢迎优秀的你&#x1f44d;点赞、&#x1f5c2;️收藏、加❤️关注哦。 本文章CSDN首发&#xff0c;欢迎转载&#xff0c;要注明出处哦&#xff01; 先感谢优秀的你能认真的看完本文&…

发送HTTP POST请求并处理响应

发送HTTP POST请求并处理响应是Web开发中的常见任务。在Go语言中&#xff0c;可以使用net/http包来发送HTTP POST请求并处理响应。 以下是一个示例代码&#xff0c;演示了如何发送HTTP POST请求并处理响应&#xff1a; go复制代码 package main import ( "b…

代码随想录算法训练营day10|232.用栈实现队列、225.用队列实现栈

理论基础 232.用栈实现队列 225. 用队列实现栈 理论基础 了解一下 栈与队列的内部实现机智&#xff0c;文中是以C为例讲解的。 文章讲解&#xff1a;代码随想录 232.用栈实现队列 大家可以先看视频&#xff0c;了解一下模拟的过程&#xff0c;然后写代码会轻松很多。 题目链…

Maven 依赖传递和冲突、继承和聚合

一、依赖传递和冲突 1.1 Maven 依赖传递特性 1.1.1 概念 假如有三个 Maven 项目 A、B 和 C&#xff0c;其中项目 A 依赖 B&#xff0c;项目 B 依赖 C。那么我们可以说 A 依赖 C。也就是说&#xff0c;依赖的关系为&#xff1a;A—>B—>C&#xff0c; 那么我们执行项目 …