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 abc" means adding c to each of Aa, Aa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q ab" 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
Hint
The sums may exceed the range of 32-bit integers.
题意:给你n个整数和q个操作,有两种操作,C l r x表示把[l, r]中所有数都加x,Q l r表示输出[l, r]中数值的和。
用线段树和树状数组都能做。
方法一:线段树。因为操作一需要修改一个区间内所有的值,所以最坏情况下需要修改整个线段树,复杂度太高。所以可以用线段树来维护两个值,一个是区间共同加上的值,一个是除了这些共同值以外其他的值的和。
#include <iostream> #include <sstream> #include <fstream> #include <string> #include <map> #include <vector> #include <list> #include <set> #include <stack> #include <queue> #include <deque> #include <algorithm> #include <functional> #include <iomanip> #include <limits> #include <new> #include <utility> #include <iterator> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <cmath> #include <ctime> using namespace std; typedef long long ll; const int maxn = (1 << 18) - 1; int n, q; //data维护区间共同值,datb维护除了这些共同值以外的值的和 ll data[maxn], datb[maxn]; //对区间[a, b)同时加x //k是节点的编号,对应的区间是[l, r) void add(int a, int b, int x, int k, int l, int r) { if (a <= l && b >= r) data[k] += x; else if (b > l && a < r) { datb[k] += (min(b, r) - max(a, l)) * x; add(a, b, x, k*2+1, l, (l+r)/2); add(a, b, x, k*2+2, (l+r)/2, r); } } //计算[a, b)的和 //k是节点的编号,对应的区间是[l, r) ll sum(int a, int b, int k, int l, int r) { if (b <= l || a >= r) return 0; if (a <= l && b >= r) return (r - l) * data[k] + datb[k]; ll res = (min(b, r) - max(a, l)) * data[k]; res += sum(a, b, k*2+1, l, (l+r)/2); res += sum(a, b, k*2+2, (l+r)/2, r); return res; } int main() { cin >> n >> q; for (int i = 0; i < n; ++i) { int num; scanf("%d", &num); add(i, i+1, num, 0, 0, n); } while (q--) { char s[5]; int l, r, x; scanf("%s", s); if (s[0] == 'C') { scanf("%d%d%d", &l, &r, &x); add(l-1, r, x, 0, 0, n); } else { scanf("%d%d", &l, &r); printf("%lld\n", sum(l-1, r, 0, 0, n)); } } return 0; }
方法二:树状数组。类似地,构建两个树状数组即可。
#include <iostream> #include <sstream> #include <fstream> #include <string> #include <map> #include <vector> #include <list> #include <set> #include <stack> #include <queue> #include <deque> #include <algorithm> #include <functional> #include <iomanip> #include <limits> #include <new> #include <utility> #include <iterator> #include <cstdio> #include <cstdlib> #include <cstring> #include <cctype> #include <cmath> #include <ctime> using namespace std; typedef long long ll; const int maxn = 100010; int n, q; //BIT ll bit0[maxn], bit1[maxn]; ll sum(ll* b, int i) { ll s = 0; while (i > 0) { s += b[i]; i &= i - 1; } return s; } void add(ll* b, int i, int x) { while (i <= n) { b[i] += x; i += i & (-i); } } int main() { cin >> n >> q; for (int i = 1; i <= n; ++i) { int num; scanf("%d", &num); add(bit0, i, num); } while (q--) { char s[5]; int l, r, x; scanf("%s", s); if (s[0] == 'C') { scanf("%d%d%d", &l, &r, &x); add(bit0, l, -x*(l-1)); add(bit1, l, x); add(bit0, r+1, x*r); add(bit1, r+1, -x); } else { scanf("%d%d", &l, &r); ll res = 0; res += sum(bit0, r) + sum(bit1, r) * r; res -= sum(bit0, l-1) + sum(bit1, l-1) * (l - 1); printf("%lld\n", res); } } return 0; }
版权声明:本文为博主原创文章,转载请注明出处。