树状数组(单点修改,区间询问)


题目描述

输入一个数列A1,A2….An(1<= N <=100000),在数列上进行M(1<=M <=100000)次操作,操作有以下两种:
(1)格式为C I X,其中C为字符“C”,I和X(1<= I<= N, |X| <=10000)都是整数,表示把把a[I]改为X
(2)格式为Q L R,其中Q为字符“Q”,L和R表示询问区间为[L,R](1<= L <= R <= N),表示询问A[L]+…+A[R]的值。

输入格式 1319.in

第一行输入N(1<= N <=100000),表述数列的长度,接下来N行,每行一个整数(绝对值不超过10000)依次输入每个数;接下来输入一个整数M(1<= M <=100000),表示操作数量,接下来M行,每行为C I X或者Q L R。

输出格式 1319.out

对于每个Q L R 的操作输出答案。

输入样例 1319.in

5
1
2
3
4
5
3
Q 2 3
C 3 9
Q 1 4

输出样例 1319.out

5
16

【解题思路】

单点修改时向上修改,区间询问时向前询问。要求区间[x,y]之间的和,就求sum(y)-sum(x-1)的值。至于树状数组针对的是加上某值,而题意中说的“改为某值”,则操作时加上的是(要改的值-原本的值)。

 

【AC代码】

#include
#include
#include
#include
#include
using namespace std;

const int maxn=100010;
int n,m;
int a[maxn];
int c[maxn];
char s[2];

int lowbit(int p)
{
	return (p&(-p));
}

void add(int p,int num)
{
	while (p<=n)
	{
		c[p]+=num;
		p+=lowbit(p);//向上修改
	}
	return;
}

int query(int p)
{
	int tmp=0;
	while (p)
	{
		tmp+=c[p];
		p-=lowbit(p);//向前询问
	}
	return tmp;
}

int main()
{
	freopen("1319.in","r",stdin);
	freopen("1319.out","w",stdout);
	scanf("%d",&n);
		memset(a,0,sizeof(a));//初始为0
		memset(c,0,sizeof(c));
		for (int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			add(i,a[i]);//加上a[i]
		}
		scanf("%d",&m);
		for (int i=1;i<=m;i++)
		{
			scanf("%s",s);
			if (s[0]=='C')
			{
				int j,k;
				scanf("%d%d",&j,&k);
				add(j,k-a[j]);// 加上的是(要改的值-原本的值)。
				a[j]=k;//更新原数组的值
			}else
			{
				int l,r;
				scanf("%d%d",&l,&r);
				int sum=query(r)-query(l-1);//区间求和
				printf("%d\n",sum);
			}
		}
	return 0;
}


你可能感兴趣的:(树状数组(单点修改,区间询问))