这题用树状数组和线段树都能做,模板题。
推荐一篇讲树状数组讲得比较好的博客:掌握树状数组~彻底入门
推荐一篇讲线段树讲得比较好的博客:线段树从零开始
树状数组:(树状数组查询和修改的复杂度都是O(log n))
(注意:树状数组维护的区间下标要从1开始,不能从0开始,有些题目的输入是有0的,需要处理一下)
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<iostream>
#include<vector>
#include<map>
#include<cstdio>
#include<cstdlib>
#define ll long long
#define inf 0x3f3f3f3f//1e9+6e7
#define N 50010
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"**"<<endl
const double pi=acos(-1.0);
using namespace std;
int a[N],c[N],n;
int lowbit(int i)
{
return i&-i;//或者是return i-(i&(i-1));表示求数组下标二进制的非0最低位所表示的值
}
void update(int i,int val)//单点更新
{
while(i<=n) //while(i<=N) N ?
{
c[i]+=val;
i+=lowbit(i);//由叶子节点向上更新树状数组C,从左往右更新
}
}
int sum(int i)//求区间[1,i]内所有元素的和
{
int ret=0;
while(i>0)
{
ret+=c[i];//从右往左累加求和
i-=lowbit(i);
}
return ret;
}
int main()
{
int T;
cin>>T;
int cas=1;
char s[100];
while(T--)
{
memset(c,0,sizeof c);
memset(a,0,sizeof a);
cin>>n;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
update(i,a[i]);
}
cout<<"Case "<<cas++<<":"<<endl;
while(scanf("%s",s)&&strcmp(s,"End")!=0)
{
int i,j;
scanf("%d%d",&i,&j);
if(strcmp(s,"Add")==0)
{update(i,j);continue;}
if(strcmp(s,"Sub")==0)
{update(i,-j);continue;}
else
cout<<sum(j)-sum(i-1)<<endl;
}
}
return 0;
}
线段树:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<map>
#include<cstdlib>
#define ll long long
#define inf 0x3f3f3f3f//1e9+6e7
#define N 50010
#define debug(x) cout<<"X: "<<(x)<<endl
#define de cout<<"**"<<endl
const double pi=acos(-1.0);
using namespace std;
int sum[N<<2];
int a[N];
int n;
void push_up(int rt)
{
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
//如果求区间最大值,此处应写sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
}
void build(int l,int r,int rt)
{
if(l==r)
{sum[rt]=a[l];return ;}
int m=(l+r)>>1;
build(l,m,rt<<1);
build(m+1,r,rt<<1|1);
push_up(rt);
}
void update(int L,int c,int l,int r,int rt)
{
if(l==r)
{
sum[rt]+=c; //如果是把第i个点的之改为c,此处应写sum[rt]=c
return ;
}
int m=(l+r)>>1;
if(L<=m) update(L,c,l,m,rt<<1);
else update(L,c,m+1,r,rt<<1|1);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&r<=R)
return sum[rt];
int m=(l+r)>>1;
//
int ans=0;
if(L<=m) ans+=query(L,R,l,m,rt<<1);
if(R>m) ans+=query(L,R,m+1,r,rt<<1|1);
return ans;
//如果求区间最大值,有时候写下边代码1,有时候代码2.
/*代码1
int ans1=0,ans2=0;
if(L<=m) ans1=query(L,R,l,m,rt<<1);
if(R>m) ans2=query(L,R,m+1,r,rt<<1|1);
return max(ans1,ans2);
*/
/*代码2
if(L>m) return query(L,R,rt<<1|1);
if(R<=m) return query(L,R,rt<<1);
return max(query(L,m,rt<<1),query(m,R,rt<<1|1));
*/
}
int main()
{
int T;
cin>>T;
int cas=1;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
char s[110];
build(1,n,1);
int i,j;
cout<<"Case "<<cas++<<":"<<endl;
while(scanf("%s",s)&&strcmp(s,"End")!=0)
{
scanf("%d%d",&i,&j);
if(strcmp(s,"Add")==0)
update(i,j,1,n,1);
if(strcmp(s,"Sub")==0)
update(i,-j,1,n,1);
if(strcmp(s,"Query")==0)
cout<<query(i,j,1,n,1)<<endl;
}
}
return 0;
}