void-man

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

给出一系列操作,更新某一区间上所有数加上一个数,然后求出某一区间上所有数的和。。。

用常规的线段树模版TLE。。。数据量太大,这里有个办法是当求出某一区间上要加某个数时,用一个新变量来保存当前增量,不往下更新了。。。

然后再下次更新或者查询时候每次到一个t都进行对增量的更新,否则就一直维持这t上的增量,这样的好处是避免了不必要的更新,因为没必要每次都把某个区间

计算出它的和,只是根据需要时候再计算...

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <stack>
#include <climits>
#define MID(x,y) ((x+y)>>1)
#define L(x) (x<<1)
#define R(x) (x<<1|1)

using namespace std;

const int MAX = 100010;
struct Tnode{__int64 sum,a; int l,r;};
Tnode node[MAX*4];
int v[MAX];

void init()
{
	memset(node,0,sizeof(node));
}

void build(int t,int l,int r)
{
	node[t].l = l; node[t].r = r;
	if( l == r - 1 )
	{
		node[t].sum = v[l];
		return ;
	}
	int mid = MID(l,r);
	build(R(t),mid,r);
	build(L(t),l,mid);
	node[t].sum = node[L(t)].sum + node[R(t)].sum;
}

void update(int t,int l,int r,__int64 sum)
{
	if( node[t].l == l && node[t].r == r )//当前区间不往下更新,当前区间所有数都要增加增量a
	{
		node[t].a += sum;
		node[t].sum += sum * ( r - l );
		return ;
	}
	if( node[t].a )//否则的话开始更新这个增量a,往下传递
	{
		node[R(t)].a += node[t].a;
		node[L(t)].a += node[t].a;
		node[R(t)].sum += node[t].a*(node[R(t)].r - node[R(t)].l);
		node[L(t)].sum += node[t].a*(node[L(t)].r - node[L(t)].l);
		node[t].a = 0;
	}
	int mid = MID(node[t].l,node[t].r);
	if( l >= mid )
		update(R(t),l,r,sum);
	else
		if( r <= mid )
			update(L(t),l,r,sum);
		else
		{
			update(L(t),l,mid,sum);
			update(R(t),mid,r,sum);
		}
	node[t].sum = node[L(t)].sum + node[R(t)].sum;
}

__int64 get(int t,int l,int r)
{
	if( node[t].l == l && node[t].r == r )
		return node[t].sum;
	if( node[t].a )//查询时候同样要帮忙更新这个a
	{
		node[R(t)].a += node[t].a;
		node[L(t)].a += node[t].a;
		node[R(t)].sum += node[t].a*(node[R(t)].r - node[R(t)].l);
		node[L(t)].sum += node[t].a*(node[L(t)].r - node[L(t)].l);
		node[t].a = 0;
	}
	int mid = MID(node[t].l,node[t].r);
	if( l >= mid )
		return get(R(t),l,r);
	else
		if( r <= mid )
			return get(L(t),l,r);
		else
			return get(L(t),l,mid) + get(R(t),mid,r);
}
int main()
{
	int n,m,x,y;
	__int64 z;
	char s[5];
	while( ~scanf("%d%d",&n,&m) )
	{
		for(int i=0; i<n; i++)
			scanf("%d",&v[i]);
		init();
		build(1,0,n+1);
		while( m-- )
		{
			scanf("%s",s);
			if( s[0] == 'Q' )
			{
				scanf("%d%d",&x,&y);
				printf("%I64d\n",get(1,x-1,y));
			}
			else
			{
				scanf("%d%d%I64d",&x,&y,&z);
				if( z == 0 )
					continue;
				update(1,x-1,y,z);
			}
		}
	}
return 0;
}
posted on 2011-08-06 23:59  void-man  阅读(569)  评论(0)    收藏  举报