POJ 3648 (线段树)-A Simple Problem with Integers

题目链接:http://poj.org/problem?id=3468

题目大意:有n个数,标号为1到n;有两种操作 Q i j 代表求i到j的和。

C i j k 代表将i到k中的每个数都加上k。每个Q操作都输出一个结果。

思路:线段树的区间修改和区间求和。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define Max 1e17
#define ll long long
using namespace std;
const int INF=1e6+500;
ll n,q; 
struct node{
	ll left,right;
	ll sum;
	ll lazy;
}g[4*INF];
ll a[INF];
char c[5];
void built(ll ans,ll l,ll r)//建树 
{
	g[ans].left =l;g[ans].right =r;
	g[ans].lazy =0;
	if(l==r)
	{
		g[ans].sum =a[l];return; 
	}
	ll mid=(l+r)/2;
	built(ans<<1,l,mid);
	built(ans<<1|1,mid+1,r);
	g[ans].sum =g[ans<<1].sum +g[ans<<1|1].sum ;
}
void pushdown(ll k)//下传标记,更改子区间的值
{
	if(g[k].lazy ==0)return ;
	ll x=g[k].lazy ;
	g[k<<1].sum =g[k<<1].sum+(g[k<<1].right -g[k<<1].left +1)*x ;
	g[k<<1|1].sum =g[k<<1|1].sum+(g[k<<1|1].right -g[k<<1|1].left +1)*x ;
	g[k<<1].lazy +=g[k].lazy ;
	g[k<<1|1].lazy +=g[k].lazy ;
	g[k].lazy =0;//清零
}
void update(ll ans,ll l,ll r,ll x)//更新 
{
	if(g[ans].left >=l&&g[ans].right <=r)//这里不能改为==,原因是下面的子区间判断时,会增加情况(不确定,若改为这样则runtime error)
	{
		g[ans].sum =g[ans].sum+(g[ans].right -g[ans].left +1)*x ;
		g[ans].lazy +=x;//这里时‘+=’的原因是:可能有连续的两个更改区间的操作,
		//前一操作时当这个区间满足更新条件更新了,但是其子区间不一定也得到了更新。 
		return;
	}
	pushdown(ans);
	ll mid=(g[ans].left +g[ans].right )/2;
	if(r>mid)update(ans<<1|1,l,r,x);//右儿子是(mid+1,r); 
	if(l<=mid)update(ans<<1,l,r,x);//左儿子是(l,mid); 
	g[ans].sum =g[ans<<1].sum +g[ans<<1|1].sum ;
}
ll find(ll ans,ll l,ll r)
{
	pushdown(ans);
	if(g[ans].left >=l&&g[ans].right <=r)
	{
		return g[ans].sum ;
	}
	ll mid=(g[ans].right +g[ans].left )/2;
	ll x=0;
	if(r>mid)x+=find(ans<<1|1,l,r);
	if(l<=mid)x+=find(ans<<1,l,r);
	return x;
}
int main()
{
	scanf("%lld%lld",&n,&q);
	ll i,j,val,k;
	ll l;
	for(i=1;i<=n;i++)
	    scanf("%lld",&a[i]);
	built(1,1,n);
	for(i=0;i<q;i++)
	{
        scanf("%s",c);
		if(strcmp(c,"Q")==0)
		{
	        scanf("%lld%lld",&j,&k);
			printf("%lld\n",find(1,j,k));		
		}		
		else if(strcmp(c,"C")==0)
		{
			scanf("%lld%lld%lld",&j,&k,&l); 
			update(1,j,k,l);
		}
	}
	return 0;
}

 

#include<iostream>//另一种代码 ,两者差不多
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define Max 1e17
#define ll long long
using namespace std;
const int INF=1e6+500;
ll n,q; 
struct node{
	ll left,right;
	ll sum;
	ll lazy;
}g[4*INF];
ll a[INF];
char c[5];
void built(ll ans,ll l,ll r)
{
	g[ans].left =l;g[ans].right =r;
	g[ans].lazy =0;
	if(l==r)
	{
		g[ans].sum =a[l];return; 
	}
	ll mid=(l+r)/2;
	built(ans<<1,l,mid);
	built(ans<<1|1,mid+1,r);
	g[ans].sum =g[ans<<1].sum +g[ans<<1|1].sum ;
}
void pushdown(ll k)
{
	if(g[k].lazy ==0)return ;
	ll x=g[k].lazy ;
	g[k<<1].sum =g[k<<1].sum+(g[k<<1].right -g[k<<1].left +1)*x ;
	g[k<<1|1].sum =g[k<<1|1].sum+(g[k<<1|1].right -g[k<<1|1].left +1)*x ;
	g[k<<1].lazy +=g[k].lazy ;
	g[k<<1|1].lazy +=g[k].lazy ;
	g[k].lazy =0;
}
void update(ll ans,ll l,ll r,ll x)
{
	if(g[ans].left ==l&&g[ans].right ==r)//这里这样写也可left>=l&&right<=r
	{
		g[ans].sum =g[ans].sum+(g[ans].right -g[ans].left +1)*x ;
		g[ans].lazy +=x;//这里+=的原因是这个区间内的值并没有得到及时的更新,而还会有改变区间数值的操作。 
		return;
	}
	pushdown(ans);
	ll mid=(g[ans].left +g[ans].right )/2;
	if(r<=mid)update(ans<<1,l,r,x);
	else if(l>mid)update(ans<<1|1,l,r,x);
	else {
		update(ans<<1,l,mid,x);
		update(ans<<1|1,mid+1,r,x);
	}
	g[ans].sum =g[ans<<1].sum +g[ans<<1|1].sum ;
}
ll find(ll ans,ll l,ll r)
{

	if(g[ans].left ==l&&g[ans].right ==r)//这里这样写也可left>=l&&right<=r

	{
		return g[ans].sum ;
	}
	pushdown(ans);
	ll mid=(g[ans].right +g[ans].left )/2;
	if(r<=mid)return find(ans<<1,l,r);
	else if(l>mid)return find(ans<<1|1,l,r);
	else return (find(ans<<1,l,mid)+find(ans<<1|1,mid+1,r));
}
int main()
{
	scanf("%lld%lld",&n,&q);
	ll i,j,val,k;
	ll l;
	for(i=1;i<=n;i++)
	    scanf("%lld",&a[i]);
	built(1,1,n);
	for(i=0;i<q;i++)
	{
        scanf("%s",c);
		if(strcmp(c,"Q")==0)
		{
	        scanf("%lld%lld",&j,&k);
			printf("%lld\n",find(1,j,k));		
		}		
		else if(strcmp(c,"C")==0)
		{
			scanf("%lld%lld%lld",&j,&k,&l); 
			update(1,j,k,l);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值