POJ 3468 A Simple Problem with Integers (分块)
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 (分块)的更多相关文章
- POJ 3468 A Simple Problem with Integers(分块入门)
题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS Memory Limit ...
- POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询)
POJ.3468 A Simple Problem with Integers(线段树 区间更新 区间查询) 题意分析 注意一下懒惰标记,数据部分和更新时的数字都要是long long ,别的没什么大 ...
- poj 3468 A Simple Problem with Integers 【线段树-成段更新】
题目:id=3468" target="_blank">poj 3468 A Simple Problem with Integers 题意:给出n个数.两种操作 ...
- 线段树(成段更新) POJ 3468 A Simple Problem with Integers
题目传送门 /* 线段树-成段更新:裸题,成段增减,区间求和 注意:开long long:) */ #include <cstdio> #include <iostream> ...
- POJ 3468 A Simple Problem with Integers(线段树功能:区间加减区间求和)
题目链接:http://poj.org/problem?id=3468 A Simple Problem with Integers Time Limit: 5000MS Memory Limit ...
- poj 3468 A Simple Problem with Integers(线段树+区间更新+区间求和)
题目链接:id=3468http://">http://poj.org/problem? id=3468 A Simple Problem with Integers Time Lim ...
- 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 ...
- 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 ...
- poj 3468:A Simple Problem with Integers(线段树,区间修改求和)
A Simple Problem with Integers Time Limit: 5000MS Memory Limit: 131072K Total Submissions: 58269 ...
随机推荐
- 【lua学习笔记】——Notepad++ 设置运行 lua 和 python
一.设置 run -> 设置 cmd /k lua "$(FULL_CURRENT_PATH)" & PAUSE & EXIT 二.原理: cmd /k ...
- Java中创建泛型数组
Java中创建泛型数组 使用泛型时,我想很多人肯定尝试过如下的代码,去创建一个泛型数组 T[] array = new T[]; 当我们写出这样的代码时编译器会报Cannot create a gen ...
- activiti7流程实例启动
package com.zcc.acvitivi; import org.activiti.engine.ProcessEngine;import org.activiti.engine.Proces ...
- CF963
CF963C 首先假设横向被分成p块纵向被分成q块,\(C_i\)为横向长度为\(i\)的方块个数,\(D_i\)为纵向长度为\(i\)的方块个数 \(p\times q=\)总块数T,q要是所有\( ...
- linux基础文件管理软硬链接
一.文件系统的基本结构 1.文件和目录被组成一个单根倒置树目录结构 2.文件系统从根目录下开始,用“/”表示 3.根文件系统(rootfs):root filesystem文件名区分大小写 4.以 . ...
- MNIST多图显示--Python练习
在学习TensorFlow框架时,提到用MNIST手写数字数据库进行练习,为了更直观看下里面的数据到底长啥样,用OpenCV(cv2)中的imshow函数来进行显示. 默认已经安装: numpy.te ...
- 一篇不一样的Android屏幕适配具体做法(原创)
转载请注明出处(http://www.cnblogs.com/weizhxa/p/7568090.html ) 有不正确,还请大家留言修正! 1.何谓屏幕适配:在任何设备上看起来布局都是近似的,细分也 ...
- 62. File类常用方法
为了怕混淆,先说明一些下面要出现的名词意思:例如:D:\\新建文件夹 (2)\\a.txt 和 D:\\新建文件夹 (2)\\aaaa D:\\新建文件夹 (2) 父路径 a.txt ...
- Windows cmd 打开面板
{ 打开控制面板的命令是:“control” 打开控制面板 命令: rundll32.exe shell32.dll,Control_RunDLL 结果: 显示控制面板窗口. 例子: Cal ...
- springCloud参考资料
官网: http://spring.io/projects/spring-cloud 各组件说明(中文版):https://springcloud.cc/spring-cloud-netflflix. ...