树状数组

树状数组

大家好,又见面了,我是全栈君。

线段树似乎和树状数组有这不可告人的秘密。

近期看了线段树和树状数组。在我的大脑中 树状数组是特殊的一种线段树。

线段树我好久之前就写过文章了。可是用的太少每次都忘。

所以还是写看写几次就能记住,毕竟写一次有一次的收获嘛。


如今我们来说树状数组。

以下我来说一下我个人对一个问题的方法,学一个新东西。先来知道这个问题是来解决什么样的问题 。然后我们来看这种方法的思路,不要把问题想的太复杂。

我们就拿树状数组来举个样例吧。

1,树状数组就是一种用log(n)的时间来改动和查询的数据结构。主要用来求数列的前n项和、一个区间的和等。

2,树状数组没什么复杂就是三个函数,有了这三个函数一切都攻克了。一个是用于计算的函数。一个改动函数,一个计算和的函数。就这么简单。


我们来看一下这个图先建立主要的想法

树状数组

这样看可能有些复杂。

这里的A数组就是我们输入的数列数组、

c[1]存放的是A[1],

c[2]存放的是A[2]+A[1];

c[3]存放的是A[3];

c[4]存放的是A[4]+c[3]+c[2]也就是A[1]+A[2]+A[3]+A[4];

从图中的连线就能看的出来。

我们先无论它是怎么计算出来的。

注意我们存数是从1開始的不是0.

以下我们来看一下如何来处理这样一个东西。

int lowbit(int n)
{
	return n&(-n);
}


这个函数的用处就是让你计算用的。先无论,等我说完举个样例你就明确了。

void modify(int pos,int num)
{
	while(pos<=n)
	{
		s[pos]+=num;
		pos+=lowbit(pos);
	}
}

这个函数是用来改动某个值的,就是将数组的 pos位置的数 加上 num。

这里用到了 上面的 lowbit函数了吧。

举个样例 

将c【5】+1。 那么就须要调用modify()函数了吧, 我们先将 c【5】+1,然后由于c【6】=A[5]+A[6],所以c【6】也须要改动。然后是c【8】(假设对这个敌法个不是非常明确我们继续往下看),这样依次往后加入。

当中5是如何到的6 而6是如何到的8 呢就是用来lowbit()这个函数。

以下这个函数是用来计算前n项的和了

int sum(int n)
{
	int num=0;
	while(n>0)
	{
		num+=s[n];
		n-=lowbit(n);
	}
	return num;
}

我们这里再来举样例可能更easy理解。

1 求前8项的和 从图中能够看到c【8】直接或间接的连接了全部的数,那么c【8】就是前8项的和 lowbit(8)就是8 所以8-8=0停止循环。

2 求前7项的和 从图中看出c【7】仅仅存储可A[7]的值那么它须要再加前6项的值,lowbit(7)=1,7-1=6。那么跳到了6 的位置。c【6】的值A[5]+A[6],我们加完了c【6】之后还须要加前4项的和。这时lowbit(6)=2,那么6-2=4,我们再加上c【4】的值,我们从图中也可已看出。c[4]存放的是A[4]+c[3]+c[2]也就是A[1]+A[2]+A[3]+A[4];

这样我们就加完了。

应该可以明确吧。

我自己測试的完整的样例。

#include<iostream>
using namespace std;
int s[10000];
int n;
int lowbit(int n)
{
	return n&(-n);
}
void modify(int pos,int num)
{
	while(pos<=n)
	{
		s[pos]+=num;
		pos+=lowbit(pos);
	}
}


int sum(int n)
{
	int num=0;
	while(n>0)
	{
		num+=s[n];
		n-=lowbit(n);
	}
	return num;
}

int main()
{
	int x;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int x;
		cin>>x;
		modify(i,x);
	}
	int m;
	while(cin>>m)
	{
		cout<<sum(m)<<endl;
	}
}

好了树状数组介绍完了。我们来看一下能做的题。


1是单点更新求区间的值。

也就是中途更新单的点的值。

这样仅仅是调用modif()函数即可了。

2是区间更新单点求值。我猜是这样一个题,在1-n上图色,看某个位置涂了几次。每次涂i-j。这样我们能够把数组初试话为0,假设这次图的是i-j的话,我们就调用modify(i,1),和modify(j,-1) 这样是有点巧妙。

3 就是求逆序数的问题了。我想后面我会写关于树状数组求逆序数的文章。

好了,感谢自己坚持 。


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/116480.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • git的pull和fetch区别_git pull和git clone

    git的pull和fetch区别_git pull和git clonegitfetch和gitpull都可以将远端仓库更新至本地那么他们之间有什么区别呢?想要弄清楚这个问题有有几个概念不得不提。FETCH_HEAD:是一个版本链接,记录在本地的一个文件中,指向着目前已经从远程仓库取下来的分支的末端版本。commit-id:在每次本地工作完成后,都会做一个gitcommit操作来保存当前工作到本地的repo,此时会产生一个commit-id,这是一个能

  • 电脑虚拟ip地址怎么弄_虚拟服务器内部端口和外部端口

    电脑虚拟ip地址怎么弄_虚拟服务器内部端口和外部端口写在前面最近,有位小伙伴为了实现Nginx的高可用,在自己的服务器上搭建了一套Nginx集群,Nginx节点的服务器总共有3台。那么问题来了:如何对外只使用一个IP地址,通过某种策略来访问三个服务器节点上的Nginx?答案就是:可以使用虚拟IP来实现!那么,如何在服务器上添加虚拟IP?今天,我们就一起实操在服务器上添加虚拟IP。实战内容这里我们创建两个虚拟机环境,IP地址分别为192.168.20…

    2022年10月12日
  • 服务器raid5阵列修复,RAID5磁盘阵列的安装与故障修复

    服务器raid5阵列修复,RAID5磁盘阵列的安装与故障修复本文将为大家简单介绍RAID5磁盘阵列的相关内容,以及在磁盘阵列发生故障后,我们应该怎么样去修复RAID5磁盘阵列的故障。有兴趣的用户,敬请关注!如何实现RAID5磁盘阵列ATARAID控制器目前市场上的RAID控制器主要有两种:1、主板上集成的IDERAID控制器,现在很多高端主板都具有集成ATARAID控制器。2、一款支持并行接口RAID5磁盘阵列模式的磐英I875P主板,以及单独的…

  • 简介支持向量机热门(认识SVM三位置)

    简介支持向量机热门(认识SVM三位置)

    2021年12月17日
  • String与Integer互相转换

    //String转换IntegerStringstr="a";Integeri=null;if(str!=null){i=Integer.valueOf(str);}//方法一:Integer类的静态方法toString():Integera=2;Stringstr=Integer.toString(a)//方法二:Integer类的…

  • Java如何定义全局变量_全局变量的默认值

    Java如何定义全局变量_全局变量的默认值有时一个项目中会多处涉及到路径,当你把这个项目移植到别的电脑上时就要一一修改这些路径,过程十分繁琐,所以一个全局变量在这时是必不可少的。遗憾的是java等oo语言并没有全局变量,这怎么办呢?下面介绍一种方法:新建一个类,包含静态属性,如下所示:publicclassVariable{/***包含项目所有的静态全局变量,项目中运行程序需要改路径时,只需修改该处变量即可*/publicstat…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号