A Simple Problem with Integers
Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 152613 Accepted: 47315
Case Time Limit: 2000MS
Description
You have N integers, A1, A2, … , AN. 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 A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.
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
问题描述
输入N,Q,分别表示整数的个数和操作的个数。然后输入N个整数Ai,再输入Q行,如果是“C a b c” 意味着对每个下标从a到b的整数再加c。如果是“Q a b”意味着输出下标从a到b的整数和。
问题分析
利用线段树区间访问和区间修改的功能可以解决,主要还是练习写线段树吧。
一些注意点:
不要用scanf_s,用VS的时候不得不用scanf_s输入,结果最后一个出错的原因就是它,把scanf_s换成scanf就好了。
区间和以及懒标记都要使用long long型。
求区间和的时候,记得对ans初始化为0,如果是作为返回值要注意类型要为long long型。
有单个字符输入的时候,用getchar吸收掉前面输入的’\n’
区间修改的时候,对子树处理后,要对父树更新(模板没学好)
c++程序如下
#include<iostream>
#include<cstdio>
using namespace std;
const int N = 100005;
typedef long long LL;
struct node
{
int L, R;
LL value, f;//f为懒标记
}tree[4*N];
void build(int l, int r, int num)//建立树
{
tree[num].L = l;
tree[num].R = r;
if (l == r)//叶子
{
scanf("%lld", &tree[num].value);
tree[num].f = 0;
return;
}
int mid = (l + r) / 2;
build(l, mid, num * 2);//左子树
build(mid + 1, r, num * 2 + 1);//右子树
tree[num].value = tree[num * 2].value + tree[num * 2 + 1].value;//状态合并
tree[num].f = 0;
}
void down(int num)//下传
{
tree[2 * num].f += tree[num].f;
tree[2 * num + 1].f += tree[num].f;
tree[2 * num].value += (tree[2 * num].R - tree[2 * num].L + 1)*tree[num].f;
tree[2 * num+1].value += (tree[2 * num+1].R - tree[2 * num+1].L + 1)*tree[num].f;
tree[num].f = 0;
}
void ask(const int&l, const int&r, int num, LL&ans)//注意ans初始化为0
{
if (tree[num].L >= l&&tree[num].R <= r)
{
ans += tree[num].value;
return;
}
if (tree[num].f) down(num);
int mid = (tree[num].L + tree[num].R) / 2;
if (mid >= l) ask(l, r, num * 2, ans);//该节点的左区域与提供的区域有重叠的部分,那么寻找左区域
if (mid < r) ask(l, r, num * 2 + 1, ans);//该节点的右区域与提供的区域有重叠的部分,那么寻找右区域
}
void add(const int&l, const int&r, int num, const LL&ad)//区间修改
{
if (tree[num].L >= l&&tree[num].R <= r)
{
tree[num].value += (tree[num].R - tree[num].L + 1)*ad;
tree[num].f += ad;
return;
}
if (tree[num].f) down(num);
int mid = (tree[num].R + tree[num].L) / 2;
if (mid >= l) add(l, r, 2 * num, ad);
if (mid < r) add(l, r, 2 * num + 1, ad);
tree[num].value = tree[2 * num].value + tree[2 * num + 1].value;//注意更新
}
int main()
{
int n, q, a, b;
char ch;
scanf("%d %d", &n, &q);
build(1, n, 1);
while (q--)
{
getchar();//吸收'\n'
scanf("%c", &ch);
if (ch == 'Q')
{
scanf("%d %d", &a, &b);
LL ans = 0;
ask(a, b, 1, ans);
printf("%lld\n", ans);
}
else if (ch == 'C')
{
LL c;
scanf("%d %d %lld", &a, &b, &c);
add(a, b, 1, c);
}
}
return 0;
}