题解:P3374 【模板】树状数组 1
Gs_The_Wolrd · · 题解
P3374 【模板】树状数组 1 题解
题解区已经有很多奆佬了,希望可以夹缝求生。
题意
对一个数列进行两种操作:
- 将一个数加上
x 。 - 求
[x,y] 的前缀和。思考
对于这道题,即使未引入树状数组,也有暴力和前缀和和差分可以解决。
非正解复杂度分析
暴力时间复杂度
- 操作 1
O(1) 。 - 操作 2 最坏
O(n) 。
x + lowbit(x)$ 就可以访问往上一层的下标。编码很简单,只有一行
int lowbit(int x) {return x & -x;}
我更喜欢取别名:
#define lowbit(x) x & -x;
更新值
理解上一个函数之后就很简单了:
/*可以把整个过程理解为爬梯子
|-------|
|-------|
|-------|
|tree[x]| x
x:当前位置 lowbit(x):往上一个台阶的距离 tree[x]:当前位置能管理到所有值的前缀和
*/
void update(int x,int d) //最开始在x 把a[x] 加上d
{
while(x <= n) //梯子最高就n层
{
tree[x] += d; //当前位置加上d
x += lowbit(x); //往上一层
}
}
求 [x,y] 前缀和
输出和普通前缀和差不多,用 sum(x) 表示 sum(x) - sum(y - 1) 就行了。
int sum(int x)
{
//和刚刚理解方法差不多 这里是下楼梯,顺便把所有的加上
int ans = 0; //答案
while(x > 0) //最少1层
{
ans += tree[x]; //加上值
x -= lowbit(x); //往下
}
return ans;
}
至此所有的都分析完了。
AC Code
#include<bits/stdc++.h>
using namespace std;
#define pc putchar
#define lowbit(x) x & -x
typedef long long ll;
typedef pair<int,int> pii;
const int maxn = 5e5 + 10;
int n,T;
int tree[maxn];
int op,x,y;
void update(int x,int d)
{
while(x <= n)
{
tree[x] += d;
x += lowbit(x);
}
} //更新部分
int sum(int x)
{
int ans = 0;
while(x > 0)
{
ans += tree[x];
x -= lowbit(x);
}
return ans;
} //前缀和
void solve()
{
scanf("%d%d%d",&op,&x,&y);
if(op == 1) update(x,y); //操作1:更新
else printf("%d\n",sum(y) - sum(x - 1));//操作2:前缀和
} //单词操作
int main()
{
scanf("%d%d",&n,&T);
for(int i=1;i<=n;i++) scanf("%d",&x),update(i,x);
//这一行是初始化 更新当前值所有能管理到它的
while(T --) solve();
return 0;
}