文章目录
- 树状数组是什么
- 树状数组与线段树的区别与联系
- 树状数组讲解
- 点修,区查,讲解及模板
- 点查,区修讲解及模板
树状数组是什么
树状数组是一种数据结构,提供O(logn)时间内的单点修改和区间求和操作,比线段树有更优的常数因子。它利用二进制特性进行快速更新和查询,常见于数组操作问题。文章通过代码示例解释了树状数组的核心操作和单点修改、区间查询的实现原理。
树状数组与线段树的区别与联系
1.两者在复杂度上同级, 但是树状数组的常数明显优于线段树, 其编程复杂度也远小于线段树.
2.树状数组的作用被线段树完全涵盖, 凡是可以使用树状数组解决的问题, 使用线段树一定可以解决, 但是线段树能够解决的问题树状数组未必能够解决.
3.树状数组的突出特点是其编程的极端简洁性, 使用lowbit技术可以在很短的几步操作中完成树状数组的核心操作,其代码效率远高于线段树。
树状数组讲解
学树状数组之前要先知道lowbit函数
lowbit这个函数的功能就是求某一个数的二进制表示中最低的一位1,举个例子,x = 6,它的二进制为110,那么lowbit(x)就返回2,因为最后一位1表示2
lowbit函数要自己写 c++库里面没有 代码如下
int lowbit(int n)
{
return n&-n;
}
看下图我们会发现,数组的下标其实是有规律的,就比如下标为1,3,5,7的二进制最后一位1都是20 为第0层 ,下标为2,6的二进制最后一位1都是21 为第1层,下标为4的二进制最后一位1都是22 为第2层,下标为8的二进制最后一位1都是23 为第3层,这样我们就可以找到一定的规律构造s数组
s数组对本身数组区间求和有很大的帮助,下图change函数就是构建s数组的过程,query函数就是求前缀和的函数
点修,区查,讲解及模板
点修和区查的意思就如下图所示
就比如他给你一个数组个数为n
在输入数组时,咱们也把s数组构建好
然后她再给你一个下标x,和一个数y让你执行操做1,就可以执行这样的操作 change(x,y) 就可以了
如果给你两个下标让你求区间和就可以执行query(y)-query(x)
例题链接
代码如下
#include <bits/stdc++.h>
#define lowbit(x) ((x)&(-x))
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
using namespace std;
int a[500100],m,n;
void asd(int x,int y)
{
while(x<=n)
{
a[x]+=y;
x+=lowbit(x);
}
}
int sum(int x)
{
int t=0;
while(x)
{
t+=a[x];
x-=lowbit(x);
}
return t;
}
signed main()
{
IOS
int c;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
cin>>c;
asd(i,c);
}
while(m--)
{
int b,x,y;
cin>>b>>x>>y;
if(b==1)
asd(x,y);
else
cout<<sum(y)-sum(x-1)<<endl;
}
return 0;
}
点查,区修讲解及模板
点查和区修的意思如下
首先想学会这个需要先知道差分
不知道差分的点这里
看完下边就理解了
在输入数组时,咱们也把差分的s数组构建好
如果给你两个下标让你执行操作2就可以这样操作change(l,x) change(r,-x)
然后她再给你一个下标x,让你执行操做2,就可以执行这样的操作query(x)
例题链接
代码如下
#include <bits/stdc++.h>
#define lowbit(x) ((x)&(-x))
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
using namespace std;
int m,n,a[500100];
void asd(int x,int y)
{
while(x<=n)
{
a[x]+=y;
x+=lowbit(x);
}
}
int sum(int x)
{
int t=0;
while(x)
{
t+=a[x];
x-=lowbit(x);
}
return t;
}
signed main()
{
IOS
int c=0,d;
cin>>m>>n;
for(int i=1;i<=m;i++)
{
cin>>d;
asd(i,d-c);
c=d;
}
for(int i=1;i<=n;i++)
{
int b,x,y,t;
cin>>b;
if(b==1)
{
cin>>x>>y>>t;
asd(x,t);
asd(y+1,-t);
}
else
{
cin>>x;
cout<<sum(x)<<endl;
}
}
return 0;
}