poj 3468 A Simple Problem with Integers

//正常思路,线段树模版
 
#include<stdio.h>
#define N 111111
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
long long int add[N<<2];
long long int sum[N<<2];
void pushup(int rt)
{
	sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int m)
{
	if(add[rt])
	{
		add[rt<<1]+=add[rt];
		add[rt<<1|1]+=add[rt];
		sum[rt<<1]+=(m-(m>>1))*add[rt];
		sum[rt<<1|1]+=(m>>1)*add[rt];
		add[rt]=0;
	}
}
void build(int l,int r,int rt)
{
	int m;
    add[rt]=0;
	if(l==r)
	{
		scanf("%lld",&sum[rt]);
		return ;
	}
	m=(l+r)>>1;
	build(lson);
	build(rson);
	pushup(rt);
}
void update(int L,int R,int c,int l,int r,int rt)
{
	int m;
	if(L<=l&&R>=r)
	{
		add[rt]+=c;
		sum[rt]+=c*(r-l+1);
		return ;
	}
	pushdown(rt,r-l+1);
	m=(l+r)>>1;
	if(L<=m)
		update(L,R,c,lson);
	if(R>m)
		update(L,R,c,rson);
	pushup(rt);
}
long long int query(int L,int R,int l,int r,int rt)
{
	long long int m, ret=0;
	if(L<=l&&R>=r)
		return sum[rt];

	pushdown(rt,r-l+1);
	m=(l+r)>>1;
	if(L<=m)
		ret+=query(L,R,lson);
	if(R>m)
		ret+=query(L,R,rson);
	return ret;	
}
int main()
{
	int m,n;
	scanf("%d%d",&n,&m);
	build(1,n,1);

	while(m--)
	{
		char s[5];
		int a,b,c;
		scanf("%s",s);
		if(s[0]=='Q')
		{

			scanf("%d%d",&a,&b);

			printf("%lld\n",query(a,b,1,n,1));

		}
		else
		{
			scanf("%d%d%d",&a,&b,&c);
			update(a,b,c,1,n,1);
		}
	}
	return 0;
}


 

下面是另一种思路

线段树维护的是以下2个数据

*给这个节点对应的区间内的所有元素共同加的值(如果只有一部分区间,就执行b)

*在这个节点的对应区间中除去a中之外其它值的和

#include<stdio.h>
#define MN 111111
int N,Q;
char T[6];
long long int data[MN<<2],datb[MN<<2];
int min(int x,int y)
{
	return x>y?y:x;
}
int max(int x,int y)
{
	return x>y?x:y;
}
void add(int a,int b,int x,int k,int l,int r)
{
	if(a<=l&&r<=b)
		data[k]+=x;
	else
		if(l<b&&a<r)
		{
			datb[k]+=(min(b,r)-max(a,l))*x;
			add(a,b,x,k*2+1,l,(l+r)/2);
			add(a,b,x,k*2+2,(l+r)/2,r);
		}
}
long long int sum(int a,int b,int k,int l,int r)
{
	long long int res=0;
	if(b<=l||r<=a)
		return 0;
	else
		if(a<=l&&r<=b)
			return data[k]*(r-l)+datb[k];
	    else
		{
			res=(min(b,r)-max(a,l))*data[k];
			res+=sum(a,b,k*2+1,l,(l+r)/2);
			res+=sum(a,b,k*2+2,(l+r)/2,r);
			return res;
		}		
}
int main(void)
{
	int i,a,b,c;
	scanf("%d%d",&N,&Q);
	for(i=0;i<N;i++)
	{
		scanf("%d",&a);
	
		add(i,i+1,a,0,0,N);
	}
	for(i=0;i<Q;i++)
	{
		scanf("%s",T);
		if(T[0]=='C')
		{
			scanf("%d%d%d",&a,&b,&c);
		    add(a-1,b,c,0,0,N);
		}
		else
		{
			scanf("%d%d",&a,&b);
			printf("%lld\n",sum(a-1,b,0,0,N));
		}

	}

}


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值