1.单点更新,区间查询
更新的是每一个点,求的是区间和
原地址HDU1166
敌兵布阵 - HDU 1166 - Virtual Judge
#include <bits/stdc++.h>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
#define ts \
ios::sync_with_stdio(false); \
cin.tie(0);
#define endl '\n'
#define pb push_back
typedef long long ll;
int a[50005], c[50005], n; //原始数组 树状数组
int lowbit(int x) //树状数组最核心功能
{
//方法一
return x - (x & (x - 1));
//方法二
return x & -x;
}
int getsum(int x) //求区间前x项的和
{ //时间复杂度O(log n)
int sum = 0;
while (x)
{
sum += c[x];
x -= lowbit(x);
}
return sum;
}
void update(int x, int v, int flag) //单点更新 v表示变化量
{
if (flag == 1) //表示增加人数
{
while (x <= n)
{
c[x] += v;
x += lowbit(x); //包含x的营地
}
}
else //减少人数
{
while (x <= n)
{
c[x] -= v;
x += lowbit(x);
}
}
}
int main()
{
ts;
int t;
cin >> t;
for (int tot = 1; tot <= t; tot++)
{
memset(a,0,sizeof a);
memset(c,0,sizeof c);
cout << "Case " << tot << ':' << endl;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
update(i, a[i], 1);
}
string s;
while (cin >> s)
{
int a, b;
if (s == "Query")
{
cin >> a >> b;
cout << getsum(b) - getsum(a - 1) << endl; //求区间的总人数
}
if (s == "Add") //增加人数
{
cin >> a >> b;
update(a, b, 1);
}
if (s == "Sub") //减少人数
{
cin >> a >> b;
update(a, b, 2);
}
if (s == "End")
break;
}
}
return 0;
}
2.区间更新,单点查询
更新的是区间,求的是单点
原数组为a,树状数组为c,其中c[i]=a[i]-a[i-1],则可以通过求树状数组c的前缀和来实现单点查询a[i].
区间修改
当给区间[l,r]修改x的时候,a[l]与a[l-1]的差值增加了x,a[r+1]与a[r]的差值减少了x。我们只需要对树状数组c[l]加上x和对c[r+1]减去x即可。
1 int n,m;
2 int a[50005] = {0},c[50005]; //对应原数组和树状数组
3
4 int lowbit(int x){
5 return x&(-x);
6 }
7
8 void updata(int i,int k){ //在i位置加上k
9 while(i <= n){
10 c[i] += k;
11 i += lowbit(i);
12 }
13 }
14
15 int getsum(int i){ //求D[1 - i]的和,即A[i]值
16 int res = 0;
17 while(i > 0){
18 res += c[i];
19 i -= lowbit(i);
20 }
21 return res;
22 }
23
24 int main(){
25 cin>>n;27 for(int i = 1; i <= n; i++){
28 cin>>a[i];
29 updata(i,a[i] - a[i-1]); //输入初值的时候,也相当于更新了值
31 }
32
33 //[x,y]区间内加上k
34 updata(x,k); //A[x] - A[x-1]增加k
35 updata(y+1,-k); //A[y+1] - A[y]减少k
36
37 //查询i位置的值
38 int sum = getsum(i);
39
40 return 0;
41 }