Description
一行N个方格,开始每个格子里的数都是0。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。1≤N≤100000,提问和修改的总数可能达到100000条。
Input
20 //方格个数
6 //有几组操作
M 1 1 //表示修改,第一个表示格子位置,第二个数表示在原来的基础上加上的数,
M 2 2
M 3 4
M 3 -5
M 6 7
C 2 6 //表示统计 ,第一个数表示起始位置,第二个数表示结束位置
Output
8
分析
这题就是线段树上的单点修改, 但是修改的时候要继续往下修改直道叶子节点。
每次统计的时候是一个区间,所以就需要二分,看看区间是全部在左边,还是全部在右边,还是两边都有,就继续往下递归,直到当前区间与要查找的区间重合或者到了叶子节点。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,m,tree[300001],x,y;//数组要开大一点!!要300000!
char ff;
void insert(int k,int l,int r)//[l,r]表示当前需要插入的区间,k表示树上节点编号
{
int mid=(l+r)/2;
if(l==r)//已经是单位区间
{
tree[k]+=y;//对这个点修改
return;
}
if(x<=mid) insert(k*2,l,mid);
else if(x>mid) insert(k*2+1,mid+1,r);
tree[k]+=y;
}
int cnt(int k,int l,int r,int x,int y)
{
if(r>n) return 0;//没有区间
if(x==l&&y==r) return tree[k];//要查找的区间和所在区间一样,直接返回
int mid=(l+r)/2;
if(y<=mid) return cnt(k*2,l,mid,x,y);
else if(x>mid) return cnt(k*2+1,mid+1,r,x,y);
else
{
return cnt(k*2,l,mid,x,mid)+cnt(k*2+1,mid+1,r,mid+1,y);
/*因为两边都有,所以加起来,并且查找范围也发生了变化,
可以刚好覆盖[x,y]的范围(把[x,y]分成[x,mid]和[mid+1,y])*/
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
cin>>ff;
scanf("%d%d",&x,&y);
if(ff=='M') insert(1,1,n);
else if(ff=='C') cout<<cnt(1,1,n,x,y)<<endl;//其实区间[x,y]内在统计函数里有一个累加的数值
}
return 0;
}