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.
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.
You need to answer all Q commands in order. One answer in a line.
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
4 55 9 15
Query和ans要用 long long ,这题关键是pushdown,找了好久错在哪里。。。
#include <stdio.h>
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
const int maxn = 111111;
typedef long long ll;
char cmd[2];
int n, mNum, a, b, c;
__int64 sum[maxn<<2]={0}, col[maxn<<2]={0};
void PushUp(int rt){sum[rt]=sum[rt<<1]+sum[rt<<1|1];} //!!!!!!!!!!!!!!这里是累加
//PushUp函数更新节点信息 ,这里是求最大值
void BuildTree(int l,int r,int rt){
//l,r表示当前节点区间,rt表示当前节点编号
if(l==r) {//若到达叶节点
scanf("%I64d",&sum[rt]);//储存数组值
return;
}
int m=(l+r)>>1;
//左右递归
BuildTree(l,m,rt<<1);
BuildTree(m+1,r,rt<<1|1);
//更新信息
PushUp(rt);
}
void PushDown(int rt,int k)
{
if (col[rt])
{
col[rt<<1] += col[rt]; /* caution,因为col[rt]的更新出错,WA了好多次 */
col[rt<<1|1] += col[rt];
sum[rt<<1] += col[rt]*(k-(k>>1));
sum[rt<<1|1] += col[rt]*(k>>1);
col[rt] = 0;
}
}/* PushDown */
/*void PushDown(int rt,int ln,int rn){
//ln,rn为左子树,右子树的数字数量。
if(Add[rt]){
//下推标记
Add[rt<<1]+=Add[rt];
Add[rt<<1|1]+=Add[rt];
//修改子节点的Sum使之与对应的Add相对应
Sum[rt<<1]+=Add[rt]*ln;
Sum[rt<<1|1]+=Add[rt]*rn;
//清除本节点标记
Add[rt]=0;
}
} */
ll Query(int L,int R,int l,int r,int rt){
//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
if(L <= l && r <= R){
//在区间内,直接返回
return sum[rt];
}
PushDown(rt, r-l+1);
int m=(l+r)>>1;
//累计答案
ll ANS=0;
if(L <= m) ANS+=Query(L,R,l,m,rt<<1); //!!!!!!!!!!!!这里也是累加
if(R > m) ANS+=Query(L,R,m+1,r,rt<<1|1);
return ANS;
}
void Update(int L,int R,int C,int l,int r,int rt){//L,R表示操作区间,l,r表示当前节点区间,rt表示当前节点编号
if(L <= l && r <= R){//如果本区间完全在操作区间[L,R]以内
sum[rt]+=C*(r-l+1);//更新数字和,向上保持正确
col[rt]+=C;//增加Add标记,表示本区间的Sum正确,子区间的Sum仍需要根据Add的值来调整
return ;
}
int m=(l+r)>>1;
PushDown(rt, r-l+1);//下推标记
//这里判断左右子树跟[L,R]有无交集,有交集才递归
if(L <= m) Update(L,R,C,l,m,rt<<1);
if(R > m) Update(L,R,C,m+1,r,rt<<1|1);
PushUp(rt);//更新本节点信息
}
int main()
{
scanf("%d %d", &n, &mNum);
BuildTree(1, n, 1);
for (int i=1; i<=mNum; ++i)
{
scanf("%s", cmd);
if (cmd[0] == 'Q')
{ /* Query */
scanf("%d %d", &a, &b);
printf("%I64d\n", Query(a, b, 1, n, 1));
}
else
{ /* Add */
scanf("%d %d %d", &a, &b, &c);
Update(a, b, c, 1, n, 1);
}
}/* End of For */
return 0;
}