题目描述
如题,已知一个数列,你需要进行下面两种操作:
1.将某区间每一个数加上x
2.求出某区间每一个数的和
输入输出格式
输入格式:
第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k
操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和
输出格式:
输出包含若干行整数,即为所有操作2的结果。
输入输出样例
输入样例#1: 复制
5 5 1 5 4 2 3 2 2 4 1 2 3 2 2 3 4 1 1 5 1 2 1 4
输出样例#1: 复制
11 8 20
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据已经过加强^_^,保证在int64/long long数据范围内)
样例说明:
#include<iostream>
using namespace std;
const int maxn = 100010;
int n, m, p, x, a, b;
long long ans;
struct Node {
long long l, r, w, f;
}node[4 * maxn + 10];
void build(int l, int r, int k) {
node[k].r = r;
node[k].l = l;
if (l == r) {
cin >> node[k].w;
return;
}
int mid = (r + l) / 2;
build(l, mid, k * 2);
build(mid + 1, r, k * 2 + 1);
node[k].w = node[k * 2].w + node[k * 2 + 1].w;
}
void down(int k) {
node[k * 2].f += node[k].f;
node[k * 2 + 1].f += node[k].f;
node[k * 2].w += (node[k * 2].r - node[k * 2].l + 1) * node[k].f;
node[k * 2 + 1].w += (node[k * 2 + 1].r - node[k * 2 + 1].l + 1) * node[k].f;
node[k].f = 0;
}
void add(int k) {
if (node[k].l >= a && node[k].r <= b) {
node[k].w += (node[k].r -node[k].l + 1) * x;
node[k].f += x;
return;
}
if (node[k].f) down(k);
int mid = (node[k].l + node[k].r) / 2;
if (a <= mid) {
add(k * 2);
}
if (b > mid) {
add(k * 2 + 1);
}
node[k].w = node[k * 2].w + node[k * 2 + 1].w;
}
void sum(int k) {
if (node[k].l >= a && node[k].r <= b) {
ans += node[k].w;
return;
}
if (node[k].f) down(k);
int mid = (node[k].l + node[k].r) / 2;
if (a <= mid) {
sum(k * 2);
}
if (b > mid) {
sum(k * 2 + 1);
}
}
int main () {
cin >> n >> m;
build(1, n, 1);
for (int i = 1; i <= m; i++) {
cin >> p;
ans = 0;
if (p == 1) {
cin >> a >> b >> x;
add(1);
} else {
cin >> a >> b;
sum(1);
cout << ans << endl;
}
}
return 0;
}
题目描述
如题,已知一个数列,你需要进行下面三种操作:
1.将某区间每一个数乘上x
2.将某区间每一个数加上x
3.求出某区间每一个数的和
输入输出格式
输入格式:
第一行包含三个整数N、M、P,分别表示该数列数字的个数、操作的总个数和模数。
第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。
接下来M行每行包含3或4个整数,表示一个操作,具体如下:
操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k
操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k
操作3: 格式:3 x y 含义:输出区间[x,y]内每个数的和对P取模所得的结果
输出格式:
输出包含若干行整数,即为所有操作3的结果。
输入输出样例
输入样例#1: 复制
5 5 38 1 5 4 2 3 2 1 4 1 3 2 5 1 2 4 2 2 3 5 5 3 1 4
输出样例#1: 复制
17 2
说明
时空限制:1000ms,128M
数据规模:
对于30%的数据:N<=8,M<=10
对于70%的数据:N<=1000,M<=10000
对于100%的数据:N<=100000,M<=100000
(数据已经过加强^_^)
样例说明:
故输出应为17、2(40 mod 38=2)
思路:该题比较复杂,因为存在俩个不同的改变区域的方案,因此我设计了俩个懒标签,同时因为要取模,所以有俩种方案的优先级可以选择,一种是先加后乘,另外一种是先乘后加,都是用在更新结点上,如果我们采取前者的方案可能存在精度损失,所以我们选择后者,其他的具体看代码,注意down里面的代码和一个懒标记很不一样,其他也有一些部分需要稍微改改,总的来说这个题目真的是一个很不错的模板题
#include<iostream>
using namespace std;
const int maxn = 100010;
struct Node{
long long l, r, w, add, mul;
}node[4 * maxn + 10];
long long a, b, x, n, m, z, p, ans;
void build(int l, int r, int k) {
node[k].r = r;
node[k].l = l;
node[k].mul = 1;
if (l == r) {
cin >> node[k].w;
return;
}
int mid = (l + r) / 2;
build(l, mid, k * 2);
build(mid + 1, r, k * 2 + 1);
node[k].w = (node[k * 2].w + node[k * 2 + 1].w) % p;
}
void down(int k) {
node[k * 2].w = (node[k].mul * node[k * 2].w + node[k].add * (node[k * 2].r - node[k * 2].l + 1)) % p;
node[k * 2 + 1].w = (node[k].mul * node[k * 2 + 1].w + node[k].add * (node[k * 2 + 1].r - node[k * 2 + 1].l + 1)) % p;
node[k * 2].mul = (node[k].mul * node[k * 2].mul) % p;
node[k * 2 + 1].mul = (node[k].mul * node[k * 2 + 1].mul) % p;
node[k * 2].add = (node[k].mul * node[k * 2].add + node[k].add) % p;
node[k * 2 + 1].add = (node[k].mul * node[k * 2 + 1].add + node[k].add) % p;
node[k].mul = 1;
node[k].add = 0;
}
void add(int k) {
if (a <= node[k].l && b >= node[k].r) {
node[k].w = (node[k].w + (node[k].r - node[k].l + 1) * x) % p;
node[k].add = (node[k].add + x) % p;
return;
}
if(node[k].add || node[k].mul != 1) down(k);
int mid = (node[k].l + node[k].r) / 2;
if (a <= mid) {
add(k * 2);
}
if (b > mid) {
add(k * 2 + 1);
}
node[k].w = (node[k * 2].w + node[k * 2 + 1].w) % p;
}
void mul(int k) {
if (a <= node[k].l && b >= node[k].r) {
node[k].w = (node[k].w * x) % p;
node[k].mul = (node[k].mul * x) % p;
node[k].add = (x * node[k].add) % p;
return;
}
if(node[k].add || node[k].mul != 1) down(k);
int mid = (node[k].l + node[k].r) / 2;
if (a <= mid) {
mul(k * 2);
}
if (b > mid) {
mul(k * 2 + 1);
}
node[k].w = (node[k * 2].w + node[k * 2 + 1].w) % p;
}
void sum(int k) {
if (a <= node[k].l && b >= node[k].r) {
ans = (node[k].w + ans) % p;
return;
}
if(node[k].add || node[k].mul != 1) down(k);
int mid = (node[k].l + node[k].r) / 2;
if (a <= mid) {
sum(k * 2);
}
if (b > mid) {
sum(k * 2 + 1);
}
}
int main() {
cin >> n >> m >> p;
build(1, n, 1);
for (int i = 1; i <= m; i++) {
cin >> z;
if (z == 1) {
cin >> a >> b >> x;
mul(1);
} else if (z == 2) {
cin >> a >> b >> x;
add(1);
} else {
cin >> a >> b;
ans = 0;
sum(1);
cout << ans << endl;
}
}
return 0;
}
一行N个方格,开始每个格子里都有一个整数。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。1≤N<100000,,提问和修改的总数m<10000条。
输入描述 Input Description
输入文件第一行为一个整数N,接下来是n行n个整数,表示格子中原来的整数。接下一个正整数m,再接下来有m行,表示m个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和。
输出描述 Output Description
共m行,每个整数
样例输入 Sample Input
6
4
5
6
2
1
3
4
1 3 5
2 1 4
1 1 9
2 2 6
样例输出 Sample Output
22
22
数据范围及提示 Data Size & Hint
1≤N≤100000, m≤10000 。
#include<iostream>
using namespace std;
const int maxn = 100000;
int n, x, y, p, ans, m;
struct node {
int l, r, w;
}tree[4 * maxn + 10];
void build(int l, int r, int k) {
tree[k].l = l;
tree[k].r = r;
if (l == r) {
cin >> tree[k].w;
return;
}
int mid = (l + r) / 2;
build(l, mid, k * 2);
build(mid + 1, r, k * 2 + 1);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
}
void add(int k) {
if (tree[k].l == tree[k].r) {
tree[k].w += y;
return;
}
int mid = (tree[k].l + tree[k].r) / 2;
if (x <= mid) add(k * 2);
else add(k * 2 + 1);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
}
void sum(int k) {
if (tree[k].l >= x && tree[k].r <= y) {
ans += tree[k].w;
return;
}
int mid = (tree[k].l + tree[k].r) / 2;
if (x <= mid) sum(k * 2);
if (y > mid) sum(k * 2 + 1);
}
int main() {
cin >> n;
build(1, n, 1);
cin >> m;
for (int i = 1; i <= m; i++) {
cin >> p >> x >> y;
ans = 0;
if (p == 1) {
add(1);
} else {
sum(1);
cout << ans << endl;
}
}
return 0;
}
题目描述 Description
给你N个数,有两种操作
1:给区间[a,b]的所有数都增加X
2:询问第i个数是什么?
输入描述 Input Description
第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数。如果第一个数是1,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果是2,后面跟1个整数i, 表示询问第i个位置的数是多少。
输出描述 Output Description
对于每个询问输出一行一个答案
样例输入 Sample Input
3
1
2
3
2
1 2 3 2
2 3
样例输出 Sample Output
5
数据范围及提示 Data Size & Hint
数据范围
1<=n<=100000
1<=q<=100000
#include<iostream>
using namespace std;
const int maxn = 100010;
int n, m, p, x, a, b, ans;
struct node {
int l, r, w, f;
}tree[4 * maxn + 10];
void build(int l, int r, int k) {
tree[k].l = l;
tree[k].r = r;
if (l == r) {
cin >> tree[k].w;
return;
}
int mid = (l + r) / 2;
build(l, mid, k * 2);
build(mid + 1, r, k * 2 + 1);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
}
void down(int k) {
tree[k * 2].f += tree[k].f;
tree[k * 2 + 1].f += tree[k].f;
tree[2 * k].w += tree[k].f * (tree[k * 2].r - tree[k * 2].l + 1);
tree[2 * k + 1].w += tree[k].f * (tree[k * 2 + 1].r - tree[k * 2 + 1].l + 1);
tree[k].f = 0;
}
void add(int k) {
if (tree[k].l >= a && tree[k].r <= b) {
tree[k].w += (tree[k].r - tree[k].l + 1) * x;
tree[k].f += x;
return;
}
if (tree[k].f) down(k);
int mid = (tree[k].l + tree[k].r) / 2;
if (a <= mid) add(k * 2);
if (b > mid) add(k * 2 + 1);
tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
}
void ask(int k) {
if (tree[k].l == tree[k].r) {
ans = tree[k].w;
return;
}
if (tree[k].f) down(k);
int mid = (tree[k].l + tree[k].r) / 2;
if (x <= mid) ask(k * 2);
else ask(k * 2 + 1);
}
int main () {
cin >> n;
build(1, n, 1);
cin >> m;
for (int i = 0; i < m; i++) {
cin >> p;
if (p == 1) {
cin >> a >> b >> x;
add(1);
} else {
cin >> x;
ask(1);
cout << ans << endl;
}
}
return 0;
}
题目描述 Description
给你N个数,有两种操作:
1:给区间[a,b]的所有数增加X
2:询问区间[a,b]的数的和。
输入描述 Input Description
第一行一个正整数n,接下来n行n个整数,
再接下来一个正整数Q,每行表示操作的个数,
如果第一个数是1,后接3个正整数,
表示在区间[a,b]内每个数增加X,如果是2,
表示操作2询问区间[a,b]的和是多少。
pascal选手请不要使用readln读入
输出描述 Output Description
对于每个询问输出一行一个答案
样例输入 Sample Input
3
1
2
3
2
1 2 3 2
2 2 3
样例输出 Sample Output
9
数据范围及提示 Data Size & Hint
数据范围
1<=n<=200000
1<=q<=200000
#include<iostream>
using namespace std;
const int maxn = 200010;
int n, m, p, x, a, b;
long long ans;
struct Node {
long long l, r, w, f;
}node[4 * maxn + 10];
void build (int l, int r, int k) {
node[k].l = l;
node[k].r = r;
if (l == r) {
cin >> node[k].w;
return;
}
int mid = (l + r) / 2;
build(l, mid, k * 2);
build(mid + 1, r, k * 2 + 1);
node[k].w = node[k * 2].w + node[k * 2 + 1].w;
}
void down(int k) {
node[2 * k].f += node[k].f;
node[2 * k + 1].f += node[k].f;
node[2 * k].w += (node[2 * k].r - node[2 * k].l + 1) * node[k].f;
node[2 * k + 1].w += (node[2 * k + 1].r - node[2 * k + 1].l + 1) * node[k].f;
node[k].f = 0;
}
void add(int k) {
if (node[k].l >= a && b >= node[k].r) {
node[k].w += (node[k].r - node[k].l + 1) * x;
node[k].f += x;
return;
}
if (node[k].f) down(k);
int mid = (node[k].l + node[k].r) / 2;
if (a <= mid) {
add(k * 2);
}
if (b > mid) {
add(k * 2 + 1);
}
node[k].w = node[k * 2].w + node[k * 2 + 1].w;
}
void sum(int k) {
if (node[k].l >= a && node[k].r <= b) {
ans += node[k].w;
return;
}
if (node[k].f) down(k);
int mid = (node[k].l + node[k].r) / 2;
if (a <= mid) {
sum(k * 2);
}
if (b > mid) {
sum(k * 2 + 1);
}
}
int main() {
cin >> n;
build(1, n, 1);
cin >> m;
for (int i = 0; i < m; i++) {
cin >> p;
ans = 0;
if (p == 1) {
cin >> a >> b >> x;
add(1);
} else {
cin >> a >> b;
sum(1);
cout << ans << endl;
}
}
return 0;
}
总结:其实这类的模板题写多了就熟练了,可以进行更近一步的题目的针对训练了,题目来源自洛古语codevs,有兴趣的可以登录这俩个平台然后将这几个题做一做