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
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ls(x) (x<<1)//尽量宏定义吧,不太容易出错
#define rs(x) (x<<1|1)
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
/*
太不容易了,终于过了,做了好长时间,太菜了,不过也发现了一些歌问题
1.pushdown的什么,脑子里一定要清楚(这里每次都是去pushdown的tag值,同时我们的sum值也会更新)
2.是不是需要pushup(关乎到我们的区间,如果我们每次都是去更新的是标准的 [ql,qr],我们肯定是要pushup,
因为我们只是修改了某些节点的[l,r]的一部分,然而我们没有修改 修改过后的sum[,r],所以是要pushup的;
但是如果我们每次都是把路过的区间都去 +=val*(r-l),我们就没有必要pushup了,因为我们都已经更新了所有
要修改区间的sum[]值,所以还是要理清自己的思路,想想应该怎样做
*/
struct node {
int l,r;
ll sum,tag;
int lazy;
} tree[maxn*4];
int n,m;
void build(int l,int r,int o)
{
tree[o].lazy=tree[o].tag=0;
tree[o].l=l,tree[o].r=r;
if(l==r) {
scanf("%lld",&tree[o].sum);
return;
}
int m=(l+r)>>1;
build(l,m,ls(o));
build(m+1,r,rs(o));
tree[o].sum=tree[ls(o)].sum+tree[rs(o)].sum;
}
void pushdown(int o) //更新和查询都需要pushdown
{
if(tree[o].lazy) {//就算是叶子节点的lazy,也不用担心,因为我们已经把sum加好了,不要tag也罢
tree[o].lazy=0;
if(tree[o].l!=tree[o].r) {//防止runtime error !!!
//中间节点向下走
tree[ls(o)].lazy=tree[rs(o)].lazy=1;
tree[ls(o)].tag+=tree[o].tag;
tree[ls(o)].sum+=(tree[ls(o)].r-tree[ls(o)].l+1)*tree[o].tag;
tree[rs(o)].tag+=tree[o].tag;
tree[rs(o)].sum+=(tree[rs(o)].r-tree[rs(o)].l+1)*tree[o].tag;
}
tree[o].tag=0;
}
}
void update(int l,int r,ll val,int o)
{
if(tree[o].l>=l&&tree[o].r<=r) { //固定的区间
tree[o].lazy=1;
tree[o].tag+=val;//找到要加的区间,只需要把add,放在这里就好
tree[o].sum+=(tree[o].r-tree[o].l+1)*val;
return;
}
//第二种思路 tree[o].sum+=(r-l+1)*val;//只要是经过的区间都会是[l,r]的大区间,都需要加上val,不一定跟着lazy。sum是当前节点区间性质,lazy要标记区间
pushdown(o);//有pushdown,就得有pushup???
int mid=(tree[o].l+tree[o].r)>>1;
if(r<=mid)
update(l,r,val,ls(o));
else if(l>mid)
update(l,r,val,rs(o));
else {
update(l,mid,val,ls(o));
update(mid+1,r,val,rs(o));
}
tree[o].sum=tree[ls(o)].sum+tree[rs(o)].sum;
}
/*
1.对于区间查询是有必要pushdown的,因为有可能问下面的某一区间的值,
然而我们还没有update
2.但是我们有必要pushup么,感觉没有必要,我们每次都会直接计算结果,上面都是now的答案,下面才是last的答案,所以是
没有必要pushup的
*/
ll query(int l,int r,int o)
{
if(tree[o].l>=l&&tree[o].r<=r) {
return tree[o].sum;
}
pushdown(o);
int mid=(tree[o].l+tree[o].r)>>1;
if(r<=mid)
return query(l,r,ls(o));
else if(l>mid)
return query(l,r,rs(o));
else {
ll ans1=query(l,mid,ls(o));
ll ans2=query(mid+1,r,rs(o));
return ans1+ans2;
}
}
int main()
{
while(~scanf("%d %d",&n,&m)) {
build(1,n,1);
while(m--) {
char ch;
int a,b;
ll c;
scanf(" %c",&ch);
if(ch=='C') {
scanf("%d %d %lld",&a,&b,&c);
update(a,b,c,1);
} else {
scanf("%d %d",&a,&b);
printf("%lld\n",query(a,b,1));
}
}
}
return 0;
}
第二种思路
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ls(x) (x<<1)//尽量宏定义吧,不太容易出错
#define rs(x) (x<<1|1)
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
struct node {
int l,r;
ll sum,tag;
int lazy;
} tree[maxn*4];
int n,m;
void build(int l,int r,int o)
{
tree[o].lazy=tree[o].tag=0;
tree[o].l=l,tree[o].r=r;
if(l==r) {
scanf("%lld",&tree[o].sum);
return;
}
int m=(l+r)>>1;
build(l,m,ls(o));
build(m+1,r,rs(o));
tree[o].sum=tree[ls(o)].sum+tree[rs(o)].sum;
}
void pushdown(int o) //更新和查询都需要pushdown
{
if(tree[o].lazy) {
tree[o].lazy=0;
if(tree[o].l!=tree[o].r) {
//中间节点向下走
tree[ls(o)].lazy=tree[rs(o)].lazy=1;
tree[ls(o)].tag+=tree[o].tag;
tree[ls(o)].sum+=(tree[ls(o)].r-tree[ls(o)].l+1)*tree[o].tag;
tree[rs(o)].tag+=tree[o].tag;
tree[rs(o)].sum+=(tree[rs(o)].r-tree[rs(o)].l+1)*tree[o].tag;
}
tree[o].tag=0;
}
}
void update(int l,int r,ll val,int o)
{
if(tree[o].l>=l&&tree[o].r<=r) { //固定的区间
tree[o].lazy=1;
tree[o].tag+=val;//找到要加的区间,只需要把add,放在这里就好
tree[o].sum+=(tree[o].r-tree[o].l+1)*val;
return;
}
tree[o].sum+=(r-l+1)*val;//只要是经过的区间都会是[l,r]的大区间,都需要加上val,不一定跟着lazy。sum是当前节点区间性质,lazy要标记区间
pushdown(o);//有pushdown,就得有pushup???
int mid=(tree[o].l+tree[o].r)>>1;
if(r<=mid)
update(l,r,val,ls(o));
else if(l>mid)
update(l,r,val,rs(o));
else {
update(l,mid,val,ls(o));
update(mid+1,r,val,rs(o));
}
}
ll query(int l,int r,int o)
{
if(tree[o].l>=l&&tree[o].r<=r) {
return tree[o].sum;
}
pushdown(o);
int mid=(tree[o].l+tree[o].r)>>1;
if(r<=mid)
return query(l,r,ls(o));
else if(l>mid)
return query(l,r,rs(o));
else {
ll ans1=query(l,mid,ls(o));
ll ans2=query(mid+1,r,rs(o));
return ans1+ans2;
}
}
int main()
{
while(~scanf("%d %d",&n,&m)) {
build(1,n,1);
while(m--) {
char ch;
int a,b;
ll c;
scanf(" %c",&ch);
if(ch=='C') {
scanf("%d %d %lld",&a,&b,&c);
update(a,b,c,1);
} else {
scanf("%d %d",&a,&b);
printf("%lld\n",query(a,b,1));
}
// printf("**%lld %lld %lld %lld\n",tree[9].sum,tree[10].sum,tree[11].sum,tree[24].sum);
}
}
return 0;
}