Description

You have \(N\) integers, \(A_1, A_2, ... , A_N\). You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers \(N\) and \(Q\). \(1 ≤ N,Q ≤ 100000\).

The second line contains \(N\) numbers, the initial values of \(A_1, A_2, ... , A_N\). \(-1000000000 \le A_i \le 1000000000\).

Each of the next \(Q\) lines represents an operation.

"\(C\ a\ b\ c\)" means adding c to each of \(A_a, A_{a+1}, \ ...\ , A_b\). \(-10000 \le c \le 10000\).

"\(Q\ a\ b\)" means querying the sum of \(A_a, A_{a+1}, \ ...\ , A_b\).

Output

You need to answer all \(Q\) commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.

Solution

题意

给定 \(n\) 个数和 \(q\) 个询问,询问包含两种:\(C\ a\ b\ c\) 代表区间 \([a, b]\) 的每个数加上 \(c\),\(Q\ a\ b\) 输出区间 \([a, b]\) 的和。

题解

分块

区间更新模板题,本题可以使用树状数组、线段树和分块解决,这里使用的是分块。

#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std; typedef long long ll; const int maxn = 1e5 + 10; ll a[maxn], sum[maxn], add[maxn]; // add[] 是增量标记
int L[maxn], R[maxn]; // 存放每个块的左右边界
int block[maxn]; // 存放下标为 i 的元素的块号
int n, q;
int block_size; // 块的大小 // 分块 + 预处理
void init() {
block_size = sqrt(n);
for(int i = 1; i <= block_size; ++i) {
L[i] = (i - 1) * block_size + 1;
R[i] = i * block_size;
}
// 处理最后一块
if(R[block_size] < n) {
++block_size;
L[block_size] = R[block_size - 1] + 1;
R[block_size] = n;
}
// 预处理每个块的区间和
for(int i = 1; i <= block_size; ++i) {
for(int j = L[i]; j <= R[i]; ++j) {
block[j] = i;
sum[i] += a[j];
}
}
} // 将区间 [l, r] 内的所有元素加 c
void change(int l, int r, ll c) {
int p = block[l], q = block[r]; // 取出左右区间所在的块号
if(p == q) {
// 在同一块直接块内暴力
for(int i = l; i <= r; ++i) {
a[i] += c;
}
sum[p] += c * (r - l + 1);
} else {
// 不在同一块,块内暴力,块间整块处理
for(int i = p + 1; i <= q - 1; ++i) {
add[i] += c;
}
// 块内暴力
for(int i = l; i <= R[p]; ++i) {
a[i] += c;
}
sum[p] += c * (R[p] - l + 1);
for(int i = L[q]; i <= r; ++i) {
a[i] += c;
}
sum[q] += c * (r - L[q] + 1);
}
} ll query(int l, int r) {
int p = block[l], q = block[r]; // 取出左右区间所在的块号
ll ans = 0;
if(p == q) {
for(int i = l; i <= r; ++i) {
ans += a[i];
}
ans += add[p] * (r - l + 1);
} else {
// 块间暴力
for(int i = p + 1; i <= q - 1; ++i) {
ans += sum[i] + add[i] * (R[i] - L[i] + 1); // 注意不是乘以 block_size
}
// 块内暴力
for(int i = l; i <= R[p]; ++i) {
ans += a[i];
}
ans += add[p] * (R[p] - l + 1);
for(int i = L[q]; i <= r; ++i) {
ans += a[i];
}
ans += add[q] * (r - L[q] + 1);
}
return ans;
} int main() {
scanf("%d%d", &n, &q);
for(int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
}
init();
for(int i = 0; i < q; ++i) {
char op;
getchar(); scanf("%c", &op);
int l, r;
scanf("%d%d", &l, &r);
if(op == 'C') {
ll c;
scanf("%lld", &c);
change(l, r, c);
} else {
printf("%lld\n", query(l, r));
}
}
return 0;
}

Reference

《算法竞赛进阶指南》 李煜东 著

POJ 3468 A Simple Problem with Integers (分块)的更多相关文章

  1. POJ 3468 A Simple Problem with Integers(分块入门)

    题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit ...

  2. POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询)

    POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询) 题意分析 注意一下懒惰标记,数据部分和更新时的数字都要是long long ,别的没什么大 ...

  3. poj 3468 A Simple Problem with Integers 【线段树-成段更新】

    题目:id=3468" target="_blank">poj 3468 A Simple Problem with Integers 题意:给出n个数.两种操作 ...

  4. 线段树(成段更新) POJ 3468 A Simple Problem with Integers

    题目传送门 /* 线段树-成段更新:裸题,成段增减,区间求和 注意:开long long:) */ #include <cstdio> #include <iostream> ...

  5. POJ 3468 A Simple Problem with Integers(线段树功能:区间加减区间求和)

    题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS   Memory Limit ...

  6. poj 3468 A Simple Problem with Integers(线段树+区间更新+区间求和)

    题目链接:id=3468http://">http://poj.org/problem? id=3468 A Simple Problem with Integers Time Lim ...

  7. poj 3468 A Simple Problem with Integers 线段树区间加,区间查询和

    A Simple Problem with Integers Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://poj.org/problem?i ...

  8. poj 3468 A Simple Problem with Integers 线段树区间加,区间查询和(模板)

    A Simple Problem with Integers Time Limit: 1 Sec  Memory Limit: 256 MB 题目连接 http://poj.org/problem?i ...

  9. poj 3468:A Simple Problem with Integers(线段树,区间修改求和)

    A Simple Problem with Integers Time Limit: 5000MS   Memory Limit: 131072K Total Submissions: 58269   ...

随机推荐

  1. Python selenium web UI之Chrome 与 Chromedriver对应版本映射表及下载地址和配置(windows, Mac OS)

    浏览器及驱动下载 进行web UI 自动化时,需要安装浏览器驱动webdriver,Chrome浏览器需要安装chromedriver.exe 驱动,Firefox需安装 geckodriver.ex ...

  2. js预编译的四部曲

    众所周知javascript是解释性语言,主要特点为解释一行执行一行. 而在js运行时会进行三件事:1语法分析  2.预编译  3.解释执行 语法分析会在代码执行前对代码进行通篇检查,以排除一些低级错 ...

  3. JavaScript 学习笔记(初学者)

    Java Script 基础 一. JS的简介     JavaScript是一种网页编程技术,经常用于创建动态交互网页     JavaScript是一种基于对象和事件驱动的解释性脚本语言,类似C语 ...

  4. 数据转化之JSON

    1.定义:Json(JavaScript Object Notation)是一种轻量级的数据教换模式,简单来说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结 ...

  5. jumpserver注意事项以及报错处理

    需要注意下面亮点 在使用jumpserver过程中,有一步是系统用户推送,要推送成功,client(后端服务器)要满足以下条件: 后端服务器需要有python.sudo环境才能使用推送用户,批量命令等 ...

  6. 关于Puppeteer的那些事儿

    最近开始上手一个自动化测试工具Puppeteer,来谈一谈关于它的一些事儿. Puppeteer中文文档:https://zhaoqize.github.io/puppeteer-api-zh_CN/ ...

  7. JNI原理与静态、动态注册

    前言 JNI不仅仅在NDK开发中应用,它更是Android系统中Java与Native交互的桥梁,不理解JNI的话,你就只能停留在Java Framework层.这一个系列我们来一起深入学习JNI. ...

  8. Oracle数据库创建与连接

    一.Oracle数据库的安装 1.下载Oracle数据库 网址:Oracle 数据库软件下载 | Oracle 技术网 | Oracle 由于需要注册,所以我就没有采用这种下载方式,  右击该网页查看 ...

  9. 4、Python 基础类型 -- Tuple 元祖类型

    Python 元组 Python的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号,列表使用方括号. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. 如下实例: 实例(P ...

  10. 并查集(Disjoint Set Union,DSU)

    定义: 并查集是一种用来管理元素分组情况的数据结构. 作用: 查询元素a和元素b是否属于同一组 合并元素a和元素b所在的组 优化方法: 1.路径压缩 2.添加高度属性 拓展延伸: 分组并查集 带权并查 ...