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.
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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值