首页 > 其他分享 >【笔记/模板】树状数组

【笔记/模板】树状数组

时间:2024-11-04 10:43:24浏览次数:1  
标签:单点 树状 int cin 笔记 update 查询 模板 op

原理解释

树状数组是一种通过前缀和和差分的思想所进行的维护数组,从而以 \(O(\log n)\) 的时间复杂度进行修改和查询。

一共有四种修改和查询的方式,分别是:

  • 单点修改 \(+\) 区间询问

  • 区间修改 \(+\) 单点询问

  • 单点修改 \(+\) 区间询问

  • (二维)区间修改 \(+\) 区间询问

    其中利用树状数组可以高效而简洁地处理第二、三个问题,第四个问题推荐使用【模板/笔记】线段树

查询

查询可以计算左右区间的总和,通过它们的前缀和相减求出区间和。通过上图可以发现,如果要求 \(sum_{7}\) 的值,可以发现 \(sum_{7} = tree_{7} + tree_{6} + tree_{4}\),而 \(7,6,4\) 之间有什么关联呢?

将其转化为二进制可以看出:\(7=(111)_{2},6=(110)_{2},4=(100)_{2}\),它们二进制中 \(1\) 的个数是不断减少的,而且减少的是最后一位,我们只需要在每一次加后将最后一位的 \(1\) 变为 $ 0 $ 即可。

维护

和查询一样,将一个数 \(tree_{i}\) 加上 \(k\),只需要将 \(i\) 的二进制的最后的 \(1\) 加上 \(1\),直到加的数超过了树状数组的大小。

可以定义一个函数 lowbit(x) 来求出一个二进制数的最后一位 \(1\):

int lowbit(int x)
{
	return x & -x; // 一个数的原码与上补码
}

代码实现

单点修改

void update(int x, int d) // 在第x点上加上d
{
	for (int i = x; i <= n; i += lowbit(x))
        tr[i] += d;
}

单点查询

int sum(int x)
{
	int res = 0;
    for (int i = x; i; i -= lowbit(i))
        res += tr[i];
   	return res;
}

单点修改 + 查询 主函数

int main()
{
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i ++)
	{
		cin >> x;
		update(i, x);
	}
	while (m--)
	{
		int op;
		cin >> op;
		if (op == 1)
		{
			int x, k; cin >> x >> k;
			update(x, k);
		}
		else
		{
			int x, y; cin >> x >> y;
			cout << sum(y) - sum(x - 1) << '\n';
		}
	}
	return 0;
}

区间修改 + 单点查询 主函数

int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int n, m;
	cin >> n >> m;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		update(i, a[i] - a[i - 1]);
	}
	while (m--)
	{
		int op;
		cin >> op;
		if (op == 1)
		{
			int x, y, k; cin >> x >> y >> k;
			update(x, k);
			update(y + 1, -k);
		}
		else
		{
			int x; cin >> x;
			cout << sum(x) << '\n';
		}
	}
	return 0;
}

标签:单点,树状,int,cin,笔记,update,查询,模板,op
From: https://www.cnblogs.com/ThySecret/p/18524702

相关文章

  • 【笔记/模板】树链剖分
    树链剖分树链剖分的基本思想通过将树分割成链的形式,从而把树形变为线性结构,减少处理难度。树链剖分(树剖/链剖)有多种形式,如重链剖分,长链剖分和用于Link/cutTree的剖分(有时被称作「实链剖分」),大多数情况下(没有特别说明时),「树链剖分」都指「重链剖分」。树链有如下几个特......
  • 【模板】矩阵运算
    不进行没必要的解释,主要记录模板。structMatrix{intn,m,rec[N][N]; //矩阵的长,宽和二维数组Matrix(int_n,int_m){n=_n,m=_m,memset(rec,0,sizeofrec);} //初始化函数voidreset(){n=0,m=0,memset(rec,0,sizeofrec);}......
  • 【笔记/模板】最近公共祖先(LCA)
    最近公共祖先(LCA)定义最近公共祖先(LowestCommonAncestor)简称LCA。对于一个树上的两个节点的最近公共祖先,是这两个点中的公共祖先里面离根最远的一个。性质可见OIWiki。向上标记法过程在两点中取得深度较大的一个点,让它不停的向上跳,同时标记所经过的每一个点,直到根节点,接......
  • 【笔记/模板】最小生成树
    www.luogu.com.cn概念/定义一个连通图的生成树是一个极小的连通子图,它包含图中全部的\(n\)个顶点,但只有构成一棵树的\(n-1\)条边。而最小生成树就是一个带权图的生成树,并且使得原图中边的权值最小的生成树,所谓最小是指边的权值之和小于或者等于其它生成树的边的权值之和。......
  • 【模板】Floyd算法
    Floyd算法原理Floyd算法用来求出任意两个节点之间的最短路。优点:代码少,思维简单,适用于除了负环以外的任何图。缺点:时间复杂度为\(O(n^3)\),空间复杂度为\(O(n^2)\)。而Floyd的核心原理是用动态规划实现的,定义一个二维数组\(f_{i,j}\),遍历图上的所有点\(k\),可以得......
  • 【模板】分块
    今天写分块的时候模板忘光了,故写以记之。CodeInitvoidinit(){sz=sqrt(n),block=n/sz+(n%sz!=0);for(inti=1;i<=block;i++)st[i]=(i-1)*sz+1,ed[i]=i*sz;ed[block]=n;for(inti=1;i<=block;i++)......
  • PbootCMS模板调用友情链接标签代码
    适用范围:全站任意地方标签作用:用于依次输出指定分组的友情链接调用代码:html {pboot:linkgid=*num=*}<ahref="[link:link]"title="[link:name]"><imgsrc="[link:logo]"></a>{/pboot:link}控制参数:gid=*:分组,必填num=*:数量,非必填,默认为10个可使用的列表......
  • PbootCMS模板调用幻灯片轮播图标签
    幻灯片轮播图列表:{pboot:slidenum=3gid=1}<ahref="[slide:link]"target="_blank"><imgsrc="[slide:src]"alt="[slide:title]"/></a>{/pboot:slide}控制参数:gid=*:分组,必填。num=*:数量,非必填,默认为5个。可用列表标......
  • pbootcms模板英文站搜索效果页面包屑显示优化
    打开 \apps\home\controller\SearchController.php 文件,根据版本替换代码:2.1.1版本:if(cookie('lg')=='cn'){//中文处理}else{//英文处理$content=str_replace('{pboot:pagetitle}',$this->config('search_title')?:......
  • GD32F1x模板工程的创建
    本文根据b站up主高博士_嵌入式的视频来写。视频链接:[2-3]05创建GD32F10x模板工程_哔哩哔哩_bilibili第一章:项目的创建首先创建一个文件夹,这个文件夹用来储存项目。  我们把项目的名字命名为test。  选择自己要使用的芯片,点击ok。 点击三个方块形状形成的按钮出......