树状数组与线段树入门

树状数组和线段树都是用于处理动态区间问题的数据结构。

树状数组:支持区间加法的同时区间查询区间和,以及最值;

线段树:支持区间加法的同时区间乘法的同时区间查询区间和,以及最值。

线段树的适用范围相较于树状数组更加广泛,但树状数组相对于线段树简洁很多,且常数极小。

树状数组

树状数组的空间复杂度为O(n),时间上单次查询为O(logn)。

首先我们需要知道这个定义:

lowbit(x):表示x在二进制下从低位往高位数的第一个1(最低位有效1)

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

树状数组听起来是一个树形结构,但是实际上用一个长度与操作数组同样为n的数组存储就行了

我们令一个树状数组为t[n],则t[x]表示的是从数组下标为x-lowbit(x)+1到x之间数组元素的和

∴对于单点更新: 

void update(int pos,int val){
    while(pos<=n)
        t[pos]+=val,pos+=lowbit(pos);
}

那么如何求区间和呢?

我们先设sum初始化为0,用于记录数组下标为1~pos的元素之和

树状数组最需要我们理解的一点,就是t[x]表示a[x-lowbit(x)+1]至a[x]的和

那么如果我们要求数组下标为1~pos的元素之和,是不是每次让sum加上t[pos]后,pos变为(pos-lowbit(pos)+1)-1,即pos=pos-lowbit(pos)就可以了?

因为t[x]表示t[x-lowbit(x)+1]到t[pos]的和,每次让pos跳转到这个区间的前一位((x-lowbit(x)+1)-1=x-lowbit(x))就可以了?

计算l~r的和的话,简单的容斥一下:query(r)-query(l-1)   就可以了。

int query(int pos){
    int sum=0;
    while(pos)
        sum+=t[pos],pos-=lowbit(pos);
    return sum;
}

例题 树状数组1

题目描述

如题,已知一个数列,你需要进行下面两种操作:

  • 将某一个数加上 x

  • 求出某区间每一个数的和

输入格式

第一行包含两个正整数 n,m,分别表示该数列数字的个数和操作的总个数。

第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。

接下来 m 行每行包含 3 个整数,表示一个操作,具体如下:

  • 1 x k 含义:将第 x 个数加上 k

  • 2 x y 含义:输出区间 [x,y] 内每个数的和

输出格式

输出包含若干行整数,即为所有操作 2 的结果。

代码如下:

#include
using namespace std;
typedef long long ll;
const int maxn=500001;
ll n,m,x,a,b,t[maxn];
ll lowbit(ll x){return x&-x;}
void update(ll pos,ll val){
	while(pos<=n)
		t[pos]+=val,pos+=lowbit(pos);
}
ll query(ll pos){
	ll sum=0;
	while(pos)
		sum+=t[pos],pos-=lowbit(pos);
	return sum;
}
int main()
{
	scanf("%lld%lld",&n,&m);
	for(ll i=1;i<=n;++i)
	{
		scanf("%lld",&x);
		update(i,x);
	}
	while(m--){
		scanf("%lld%lld%lld",&x,&a,&b);
		switch(x){
			case 1:
				update(a,b);
				break;
			default:
				printf("%lld\n",query(b)-query(a-1));
				break;
		}
	}
	return 0;
}

线段树

线段树的空间复杂度>=2*n,通常需要4*n避免RE,单次查询时间复杂度为O(logn)

第一次听起来非常容易理解:这是一棵树:树上任意一点都有t[x].l与t[x].r,此节点表示数组下标为t[x].l到t[x].r的元素之和

                                                       (1,8)

                               (1,4)                                         (5,8)

                   (1,2)              (3,4)             

你可能感兴趣的:(c++)