A Simple Problem with Integers
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. 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.
Source
POJ Monthly--2007.11.25, Yang Yi
|
#include<stdio.h>
#include<string.h>
#include<iostream>
#include<math.h>
#include<time.h>
#include<map>
#include<string>
#include<algorithm>
#include<set>
#define N 50000
using namespace std;
int a;
struct node
{
int L; //L-R区间
int R;
long long num; //区间值
long long lazy; //“lazy”标记
int lenth; //区间长度,用来计算更新的值,因为是区间更新
}leaves[100000*4];
void Push_Tree(int k) //这个就是神秘的更新子区间的Push函数啦!
{
if(leaves[k].lazy)
{
leaves[2*k].num = leaves[2*k].num + leaves[k].lazy*leaves[2*k].lenth; //这里下面两行是更新左右子区间的值
leaves[2*k+1].num = leaves[2*k+1].num + leaves[k].lazy*leaves[2*k+1].lenth;
leaves[2*k].lazy += leaves[k].lazy; //下面这两行又是把这个子区间当作一个父区间,进行“lazy标记”
leaves[2*k+1].lazy += leaves[k].lazy; //不去更新它的子区间
leaves[k].lazy = 0; //去除“lazy标记”,表示上次我们的懒惰已经解决了!(虽然我们又“lazy”了“子子”区间)
}
}
void Build_Tree(int l, int r, int k) //建树还是老方式
{
leaves[k].L = l;
leaves[k].R = r;
leaves[k].lazy = 0;
leaves[k].lenth = r - l + 1;
if(l == r){
scanf("%lld", &leaves[k].num);
return;
}
int mid = (l+r)/2;
Build_Tree(l, mid, 2*k);
Build_Tree(mid+1, r, 2*k+1);
leaves[k].num = leaves[2*k].num+leaves[2*k+1].num;
}
void Update_Tree(int l, int r, int add, int k) //这里我们只要找目标区间进行更新(三种情况)
{ //去看我单点更新区间查找的解释,还有图
if(leaves[k].L == l && leaves[k].R == r){
leaves[k].num += leaves[k].lenth * add;//更新目标区间的值
leaves[k].lazy += add;//进行懒惰标记
return;
}
Push_Tree(k); //子区间更新函数,为什么放在这里,可能一下理解不了,你一定要联系代码和数据
int mid = (leaves[k].L+leaves[k].R)/2; //画图模拟一下,想一下啊(很重要哦!)
if(r <= mid) Update_Tree(l, r, add, 2*k); //下面是三种情况
else if(l > mid)Update_Tree(l, r, add, 2*k+1);
else{
Update_Tree(l, mid, add, 2*k);
Update_Tree(mid+1, r, add, 2*k+1);
}
leaves[k].num = leaves[2*k].num + leaves[2*k+1].num; //父区间的值等于子区间的值(懒惰的父区间不会进行这个操作)
} //因为计算过且return了,而且你没有更新它的子区间
long long Search_Tree(int l, int r, int k)
{
if(leaves[k].L == l && leaves[k].R == r){ //查找同样的三种情况
return leaves[k].num;
}
Push_Tree(k); //我说过,查找的时候也会更新子区间的啦
int mid = (leaves[k].L+leaves[k].R)/2;
if(r <= mid) return Search_Tree(l, r, 2*k);
else if(l > mid) return Search_Tree(l, r, 2*k+1);
else{
return Search_Tree(l, mid, 2*k) + Search_Tree(mid+1, r, 2*k+1);
}
}
int main()
{
int n, m, x, y, s;
char oder[2];
scanf("%d%d", &n, &m);
Build_Tree(1, n, 1);
while(m--){
scanf("%s", oder);
if(oder[0] == 'C'){
scanf("%d%d%d", &x, &y, &s);
Update_Tree(x, y, s, 1);
}
if(oder[0] == 'Q'){
scanf("%d%d", &x, &y);
printf("%lld\n", Search_Tree(x, y, 1));
}
}
return 0;
}