题目概述:
有N个数
每个数的编号从1递增,每个数的值为num
有三种操作,M a b,计算并输出区间a到b(含a,b)的数的和,S a b,将第a个数修改为b,END操作结束
输入:
第一行N,其后N行每行一个num,再后若干行,每行一种操作,到END操作时为止,数据有多(<=3)组,到N=0时为止(不处理)
限制:
N<=2e5;0<=num<=1000;操作数<=2e5;对M操作,a<=b;对S操作,0<=b<=1000;
输出:
每组数据第一行为一个字符串,记当前为第%times%组(从1递增)数据,则字符串为
Case %times%:
其后若干行每行一个整数,为M操作结果
多组数据之间有一个空行,但最后一组数据后没有
样例输入:
3
100
100
100
M 1 1
M 1 3
S 2 200
M 1 2
S 3 0
M 2 3
END
10
1
2
3
4
5
6
7
8
9
10
M 1 10
END
0
样例输出:
Case 1:
100
300
300
200
Case 2:
55
讨论:
这里提一点多余的,沿用hdu1754的query和modify函数并简单修改一下就可以直接交,但注意,其运行时间异常缓慢(甚至可能比线段树还慢),因为以树状数组求最值时的query和modify严格说只是借用树状数组的思想,比最朴素的方法没剩下太多步骤,求最值时没有其他选择余地,而求和时仅用原始的树状数组函数足矣
至于这个树状数组本身的说明,参考hdu2352,原始的树状数组理解难度相比仅仅借用其思想(求最值)要小很多,这里也不再赘述
题解状态:
0 KB,150 ms,C++11 4.8.2,1089
#include<algorithm>
#include<string.h>//为memset而包含
using namespace std;
#define INF 0x3f3f3f3f//不是6,改成3了
#define maxx(a,b) ((a)>(b)?(a):(b))
#define minn(a,b) ((a)<(b)?(a):(b))
#define MAXN 200030
#define lb(a) (a&(-a))
int tree[MAXN];
int nums[MAXN];
char cmd[6];
inline int query(int a)
{
int sum = 0;
while (a) {
sum += tree[a];
a -= lb(a);
}
return sum;
}
inline void modify(int a, int mod)
{
while (a <= MAXN) {
tree[a] += mod;
a += lb(a);
}
}
inline void fun(int N)
{
for (int p = 1; p <= N; p++) {
scanf("%d", &nums[p]);//input
modify(p, nums[p]);
}
while (scanf("%s", cmd) && cmd[0] != 'E') {//input
int a, b;
scanf("%d%d", &a, &b);//input
switch (cmd[0]) {
case'M':
printf("%d\n", query(b)-query(a-1));//output
break;
case'S':
b -= nums[a];//由于modify函数需要的是变化值,所以这里做差
nums[a] += b;//以后的修改可能会基于已经修改过的值,因此有必要更新原始数据
modify(a, b);//这时b已经是新旧数据的差值了
break;
}
}
}
int main(void)
{
//freopen("vs_cin.txt", "r", stdin);
//freopen("vs_cout.txt", "w", stdout);
int N, kase = 0;
bool f = false;
while (~scanf("%d", &N) && N) {//input
if (f)
printf("\n");//output
printf("Case %d:\n", ++kase);//output
fun(N);
memset(tree, 0, sizeof(tree));
f = true;
}
}
附:沿用从hdu1754修改而来的query和modify函数
modify的N参数可以作为全局变量而避免传值调用,另外注意,modify的参数v是将要赋予的值,而原始树状数组的的modify函数的mod参数是相对原数值的变化值,就是加减多少,因此在fun函数中调用modify时,原版的已经呈现在上面,沿用的则在case'S':后直接调用modify(a,b,N);即可,对原始数据的修改操作已经集成
query函数也有些许差别,原版的若求区间需像题解一样做差,而沿用的直接将两个区间端点作为参数传递即可直接求得,但反过来,原版的即便求2次速度也是更快的
inline int query(int a, int b)
{
int ans = nums[b];
while (a != b) {
for (b -= 1; b - lb(b) >= a; b -= lb(b))
ans += tree[b];
ans += nums[b];
}
return ans;
}
inline void modify(int a, int v, int N)
{
nums[a] = v;
for (int p = a; p <= N; p += lb(p)) {
tree[p] = nums[p];
for (int o = 1; o < lb(p); o <<= 1)
tree[p] += tree[p - o];
}
}
EOF