专栏文章

题解:P3374 【模板】树状数组 1

P3374题解参与者 2已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mipks6d0
此快照首次捕获于
2025/12/03 13:37
3 个月前
此快照最后确认于
2025/12/03 13:37
3 个月前
查看原文

题目大意:

有一个由 nn 个数字组成的数列,对于第 ii 个数其初始值为 ii,对这个数列进行 mm 次操作:
  • 操作1:将第 xx 个数加 kk
  • 操作2:输出 aa 数组中 [x,y][x,y] 区间内的和,包括 a[x]a[x]a[y]a[y]

算法分析:

由于 nnmm 的范围均为 5×1055 \times 10^5,因此暴力绝对不可取,考虑使用树状数组解决。
关于树状数组:
  1. 简介:树状数组的学名是二叉搜索树,其利用二叉树思想的前缀和的加强版。
  2. 与二叉树的区别:简单来说,树状数组比二叉树少了大部分非叶子节点的子节点。以下两幅图帮助理解:
    (1)一个倾斜的二叉树
    (2)其对应的树状数组
    观察后可发现,一个二叉树如果只保留每一列最上面的一个节点,就是其对应的树状数组。
  3. 在本题的运用:单点修改,区间查询。
介绍一个新的概念,lowbitlowbit
  • 对于一个正整数 xx,我们规定 lowbit(x)lowbit(x) 为:二进制表示的 xx,除最后一位 11 外,其余全部改为 00,所得到的数。
  • 一般将 lowbit(i)lowbit(i) 用于求 a[i]a[i] 的父节点。
CPP
inline int lowbit(int x){
	return x&(-x);
}

Code:

CPP
#include<bits/stdc++.h>
using namespace std;
int n,m,a[500005],c[500005];
inline int lowbit(int x){
	return x&(-x);
}
void add(int i,int x){//将第i个数增加x。
	while(i<=n){
		c[i]+=x;
		i+=lowbit(i);
	}
}
int query(int x){//求a[x]到a[y]的区间和。
	int s=0;
	while(x){
		s+=c[x];
		x-=lowbit(x);
	}
	return s;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		add(i,a[i]);//为每个结点赋初值。
	}
	int op,x,y;
	scanf("%d",&m);
	for(int i=1;i<=m;i++){
		scanf("%d%d%d",&op,&x,&y);
		if(op==1){//将a[x]的值加y。
			a[x]+=y;
			add(x,y);
		}else{
			printf("%d\n",query(y)-query(x-1));//输出区间和。
		}
	}
    return 0;
}

评论

2 条评论,欢迎与作者交流。

正在加载评论...