http://acm.hdu.edu.cn/showproblem.php?pid=1166
题目是一道很经典的一维树状数组的题,改动一维数组中的一个点,求一段连续区间的和。原理可以去看训练指南,在打代码的时候要回想起那幅经典的图,修改某个值的时候,是向右上角爬,从左子树到父结点,所以是i += lowbit(i)。而查询某一段区间的时候,是向左上角爬,从右子树到父结点,所以是m -= lowbit(m)。
query(i)得到的是[1,i]的和
add(i,d)是给第i个数加上d,sub就是减去d
这道题用iostream会TLE, 还有C字符串中两个字符串的比较要用strcmp。
树状数组开得和普通数组所需要的量一样大就可以。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#define N 50001
#define VN 50001
using namespace std;
int n, a[N], c[VN];
int lowbit(int x)
{
return x & (-x);
}
int query(int m)
{
int sum = 0;
while (m > 0)
{
sum += c[m];
m = m - lowbit(m);
}
return sum;
}
void add(int i, int x)
{
while (i <= n)
{
c[i] += x;
i += lowbit(i);
}
}
void sub(int i, int x)
{
while (i <= n)
{
c[i] -= x;
i += lowbit(i);
}
}
int main()
{
int T, st, ed, site, ad, sb, cnt = 0;
char s[20];
scanf("%d", &T);
while (T--)
{
printf("Case %d:\n", ++cnt); // 注意
scanf("%d", &n);
memset(c, 0, sizeof(c));
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
add(i, a[i]);
}
while (scanf("%s", s) && strcmp(s, "End") != 0)
{
if (strcmp(s, "Query") == 0)
{
scanf("%d%d", &st, &ed);
int ans = query(ed) - query(st - 1);
printf("%d\n", ans);
}
if (strcmp(s, "Add") == 0)
{
scanf("%d%d", &site, &ad);
add(site, ad);
}
if (strcmp(s, "Sub") == 0)
{
scanf("%d%d", &site, &sb);
sub(site, sb);
}
}
}
return 0;
}