HDU - 1166 敌兵布阵 (kuangbin - 线段树)

题目描述

  Lily 特别喜欢养花,但是由于她的花特别多,所以照料这些花就变得不太容易。她把她的花依次排成一行,每盆花都有一个美观值。如果Lily把某盆花照料的好的话,这盆花的美观值就会上升,如果照料的不好的话,这盆花的美观值就会下降。有时,Lily想知道某段连续的花的美观值之和是多少,但是,Lily的算术不是很好,你能快速地告诉她结果吗?

输入格式

  第一行一个整数T,表示有T组测试数据。
每组测试数据的第一行为一个正整数N(N<=50000),表示Lily有N盆花。接下来有N个正整数,第i个正整数ai表示第i盆花的初始美观值(1<=ai<=50)。
  接下来每行有一条命令,命令有4种形式:
  (1)Add i j, i和j为正整数,表示第i盆花被照料的好,美观值增加j(j<=30)
  (2)Sub i j, i和j为正整数,表示第i盆花被照料的不好,美观值减少j(j<=30)
  (3)Query i j, i和j为正整数,i<=j,表示询问第i盆花到第j盆花的美观值之和
  (4)End,表示结束,这条命令在每组数据最后出现
每组数据的命令不超过40000条

输出格式

  对于第i组数据,首先输出"Case i:"和回车。对于每个"Query i j"命令,输出第i盆花到第j盆花的美观值之和。

输入输出样例
输入

1 9
7 9 8 4 4 5 4 2 7
Query 7 9
Add 4 9
Query 3 6
Sub 9 6
Sub 3 3
Query 1 9
End

输出

Case 1:
13
30
50

题目链接

分析:

  

这道题需要注意的地方:

  

代码如下:

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <string>
#include <cstring>
#include <map>
#include <queue>
#define MAX 50010
using namespace std;
typedef long long LL;
int read(){
	int x, f = 1;
	char ch;
	while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -1;
	x = ch - '0';
	while(ch = getchar(), ch >= '0' && ch <= '9') x = x * 10 + ch - 48;
	return x * f;
}
int tree[4 * MAX]; // 线段树
int lz[4 * MAX]; // 延迟标记
char a[8];
void build(int node, int l, int r){ // 创建线段树
	if(l == r){
		tree[node] = read();
		return;
	}
	int mid = (l + r) / 2;
	build(node * 2, l, mid);
	build(node * 2 + 1, mid + 1, r);
	tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
void update(int n, int index, int l, int r, int node){ // 单点更新,n为更新值,index为更新点,lr为更新范围
	if(l == r){
		tree[node] += n; // 更新方式,可以自由改动
		return;
	}
	int mid = (l + r) / 2;
	// push_down(node,mid-l+1,r-mid); 若既有点更新又有区间更新,需要这句话
	if(index <= mid){
		update(n, index, l, mid, node * 2);
	}else{
		update(n, index, mid + 1, r, node * 2 + 1);
	}
	tree[node] = tree[node * 2] + tree[node * 2 + 1];
}
void push_down(int node, int l, int r){
	if(lz[node]){
		int mid = (l + r) / 2;
		lz[node * 2] += lz[node];
		lz[node * 2 + 1] += lz[node];
		tree[node * 2] += 1LL * (mid - l + 1) * lz[node];
		tree[node * 2 + 1] += 1LL * (r - mid) * lz[node];
		lz[node] = 0;
	}
}
LL query_range(int node, int L, int R, int l, int r){	// 区间查找
	if(l <= L && r >= R) return tree[node];
	push_down(node, L, R);
	int mid = (L + R) / 2;
	LL sum = 0;
	if(mid >= l) sum += query_range(node * 2, L, mid, l, r);
	if(mid < r) sum += query_range(node * 2 + 1, mid + 1, R, l, r);
	return sum;
}
int main(){
	int n, i, p, q, t, u;
	t = read();
	for(i = 1; i <= t; i++){
		memset(tree, 0, sizeof(tree));
		memset(lz, 0, sizeof(lz));
		u = read();
		build(1, 1, u);
		printf("Case %d:\n", i);
		while(scanf("%s", a)){
			if(a[0] == 'E') break;
			p = read();
			q = read();
			if(a[0] == 'Q') printf("%lld\n", query_range(1, 1, u, p, q)); 
			else if(a[0] == 'A') update(q, p, 1, u, 1);
			else update(-q, p, 1, u, 1);
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值