POJ 3468 A Simple Problem with Integers (区间加区间查找)
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
Hint
The sums may exceed the range of 32-bit integers.
#include <cstdio> #include <iostream> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <queue> #include <vector> #include <map> using namespace std; #define ll long long #define eps 1e-9 const int inf = 0x3f3f3f3f; const int mod = 1e9+7; ll n, q, x, y, k, ans, a[1000000+8];///开ll,不然数据太大,加起来会爆int char c; struct node { int l, r; ll sum, plz;///开ll,不然数据太大,加起来会爆int }tree[4*1000000+8]; void build(int i, ll l, ll r) { tree[i].l = l; tree[i].r = r; tree[i].plz = 0; if(l == r)///如果已经是叶子结点 tree[i].sum = a[l]; else { ll mid = (l+r)/2; build(i*2, l, mid);///往左儿子进行建树 build(i*2+1, mid+1, r);///往右儿子进行建树 tree[i].sum = tree[i*2].sum+tree[i*2+1].sum;///父节点的和等于左儿子的和加右儿子的和 } } void push_down(int i)///把自己的lazytage归零,并给自己的儿子加上,并让自己的儿子加上k*(r-l+1) { tree[i*2].plz += tree[i].plz;///左儿子的加标记等于父节点的加标记 tree[i*2+1].plz += tree[i].plz;///右儿子的加标记等于父节点的加标记 tree[i*2].sum += tree[i].plz*(tree[i*2].r-tree[i*2].l+1);///(左儿子的和)=(左儿子的和)+(左儿子所控制的元素个数)*父节点的加标记 tree[i*2+1].sum += tree[i].plz*(tree[i*2+1].r-tree[i*2+1].l+1);///(右儿子的和)=(右儿子的和)+(右儿子所控制的元素个数)*父节点的加标记 tree[i].plz = 0;///父节点标记归零 } void pls(int i, ll l, ll r, ll k)///区间加 { if(tree[i].r == r && tree[i].l == l)///如果这个区间恰好是要查找的区间 { tree[i].plz += k;///加标记加上k,表示该区间已经在原来的基础上加了那么多东西 tree[i].sum += k*(r-l+1);///(这个区间的和)=(这个区间的和)+(要加的数)*(这个区间所控制元素的个数) return; } if(tree[i].l == tree[i].r)///如果为叶子结点,就直接返回他的值 return; push_down(i);///把自己的lazytage归零,并给自己的儿子加上,并让自己的儿子加上k*(r-l+1) ll mid = (tree[i].l+tree[i].r)/2; if(mid >= r)///如果这个点中间的值大于右边的区间,就往左儿子那边搜索 pls(i*2, l, r, k); else if(mid < l)///如果这个点中间的值小于左边的区间,就往右儿子那边搜索 pls(i*2+1, l, r, k); else///否则就是左儿子右儿子都包含有这个区间,都搜索 { pls(i*2, l, mid, k); pls(i*2+1, mid+1, r, k); } tree[i].sum = tree[i*2].sum + tree[i*2+1].sum; } void search(int i, ll l, ll r)///区间查找 { if(tree[i].l >= l && tree[i].r <= r)///如果这个区间在目标区间内 { ans += tree[i].sum; return; } push_down(i);///把自己的lazytage归零,并给自己的儿子加上,并让自己的儿子加上k*(r-l+1) ll mid = (tree[i].l+tree[i].r)/2; if(l <= mid) search(i*2, l, r);///[l, r]区间不能改,因为题目要搜索的就是[l, r]区间 if(mid<r) search(i*2+1, l, r); } int main() { scanf("%lld%lld", &n, &q); for(int i = 1; i <= n; i++) scanf("%lld", &a[i]); build(1, 1, n); for(int i = 0; i<q; i++) { ans = 0; getchar(); scanf("%c", &c); getchar(); if(c == 'C') { scanf("%lld%lld%lld", &x, &y, &k); pls(1, x, y, k); } else { scanf("%lld%lld", &x, &y); search(1, x, y); printf("%lld\n", ans); } } return 0; }