传送门:NYOJ116 士兵杀敌(二)
描述
南将军手下有N个士兵,分别编号1到N,这些士兵的杀敌数都是已知的。
小工是南将军手下的军师,南将军经常想知道第m号到第n号士兵的总杀敌数,请你帮助小工来回答南将军吧。
南将军的某次询问之后士兵i可能又杀敌q人,之后南将军再询问的时候,需要考虑到新增的杀敌数。
输入
只有一组测试数据
第一行是两个整数N,M,其中N表示士兵的个数(1<N<1000000),M表示指令的条数。(1<M<100000)
随后的一行是N个整数,ai表示第i号士兵杀敌数目。(0<=ai<=100)
随后的M行每行是一条指令,这条指令包含了一个字符串和两个整数,首先是一个字符串,如果是字符串QUERY则表示南将军进行了查询操作,后面的两个整数m,n,表示查询的起始与终止士兵编号;如果是字符串ADD则后面跟的两个整数I,A(1<=I<=N,1<=A<=100),表示第I个士兵新增杀敌数为A.
输出
对于每次查询,输出一个整数R表示第m号士兵到第n号士兵的总杀敌数,每组输出占一行
样例输入
5 6
1 2 3 4 5
QUERY 1 3
ADD 1 2
QUERY 1 3
ADD 2 3
QUERY 1 2
QUERY 1 5
样例输出
6
8
8
20
本题与上一道题相比(前缀和)NYOJ108 士兵杀敌(一) ,增加的了单点更新。
树状数组解决动态前缀和的数据结构。
树状数组是一种解决动态前缀和的数据结构,其实质是二进制拆分。树状数组单次查询的复杂度为O(log(n)).
可以解决的问题:区间和,单点更新,区间加,单点查询等问题。
对于区间加和单点查询是放在一起的概念,单点查询其实就是传统意义上的区间求和问题。
例如:对区间[3,6]中的每个数都加5
二维树状数组,
区间最值问题,更推荐线段树。
树状数组功能比线段树小,实现简单,常数小的数据结构。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000010;
int d[maxn],a;
int n,m;
int lowbit(int x){
return x&(-x);
}
int sum(int x){
int res=0;
while(x){
res+=d[x];
x-=lowbit(x);
}
return res;
}
void add(int x,int v){
while(x<=n){
d[x]+=v;
x+=lowbit(x);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a);
add(i,a);
}
int u,v;
char str[10];
while(m--){
scanf("%s%d%d",str,&u,&v);
if(strcmp(str,"QUERY")==0) printf("%d\n",sum(v)-sum(u-1));
else add(u,v);
}
return 0;
}
解析版:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1000010;
int d[maxn],a;
int n,m;
int lowbit(int x){ //返回二进制第一个非0数,例10100-->00100,110->010,001-->001
return x&(-x);
}
int sum(int x){ //查询前x项和,过程相当与对二进制的每一位进行拆分
//1101-->1100-->1000,13-->12-->8
int res=0;
while(x){
res+=d[x];
x-=lowbit(x);
}
return res;
}
void add(int x,int v){ //根据树状数组的结点规律初始化数组,例如,n==5时,x=1,对d[1]进行赋值,接着修改d[2],d[4]
while(x<=n){
d[x]+=v;
//cout<<"x="<<x<<",d["<<x<<"]="<<d[x]<<",lowbit(x)="<<lowbit(x)<<endl;
x+=lowbit(x);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a);
add(i,a);
}
int u,v;
char str[10];
while(m--){
scanf("%s%d%d",str,&u,&v);
if(strcmp(str,"QUERY")==0) printf("%d\n",sum(v)-sum(u-1));
else add(u,v);
}
return 0;
}