uva 12086

题目概述:

有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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值