poj3468(A Simple Problem with Integers)线段树实现

POJ:3468

从下午开始做,一直做到晚上八点。ACM新手,刚接触线段树。

题意很简单,Q代表查寻一段区间内Ai的和,C表示往区间内增加。


这题如果直接老方法,就是更新到结点,查询到区间的话,,,很容易就超时,

struct SegTree{
	int left,right;
	long long count , add ;
}st[MAX];

所以为做这道题得学新东西。对线段树中的更新操作中有一种算法叫延迟标记,也就是lazy算法。

算法的思想是在原来的结构体中增加一个add域,每次更新时只更新到一个大区间,并把add增加(具体增加多少看题目)。

在每次访问的时候需要把这个区间的add给往下推,这时候不要忘了对count更新,count=add*(right-left+1);

下面是代码:

/*
A Simple Problem with Integers
Time Limit: 5000MS		Memory Limit: 131072K
Total Submissions: 66090		Accepted: 20346
Case Time Limit: 2000MS
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
Hint

The sums may exceed the range of 32-bit integers.
*/

#include <stdio.h>

#define MAX 400000

struct SegTree{
	int left,right;
	long long count , add ;
}st[MAX];

void creatTree(int left , int right , int pos)
{
	st[pos].count = 0;
	st[pos].add = 0 ;
	st[pos].left = left ;
	st[pos].right = right ;
	if(left == right)
	{
		return ;
	}
	
	int mid = (left + right)>>1;
	creatTree(left , mid , pos<<1) ;
	creatTree(mid+1 , right , pos<<1|1);
}

void init(int x , int data , int pos)
{
	st[pos].count += data ;
	if(st[pos].left == st[pos].right && st[pos].left == x)
	{
		return ;
	}
	int mid = (st[pos].left + st[pos].right)>>1;
	if(x > mid)
	{
		init(x,data,pos<<1|1);
	}
	else
	{
		init(x,data,pos<<1);
	}
}

void update(int left , int right , int data , int pos)
{
	if(left == st[pos].left && right == st[pos].right)	//更新到区间,add增加		
	{
		st[pos].add += data ;
		return ;
	}
	st[pos].count += data*(right-left+1) ;                      //如果要查询的区间小于大的区间的话,更新大区间的count;
	int mid = (st[pos].left + st[pos].right)>>1;
	if(left > mid)
	{
		update(left , right , data ,pos<<1|1);
	}
	else if(right <= mid)
	{
		update(left , right , data , pos<<1);
	}
	else
	{
		update(left , mid , data , pos<<1);
		update(mid+1,right , data ,pos<<1|1);
	}
}

long long query(int left ,int right , int pos)
{
	long long sum = 0 ;
	if(st[pos].left == left && st[pos].right == right)
	{
		return st[pos].count + st[pos].add*(st[pos].right - st[pos].left + 1);
	}
	int p = pos<<1 ;
	if(st[pos].add && p+1 < MAX)                     //查询的时候,把add往下推
	{
		st[p].add += st[pos].add;
		st[p+1].add += st[pos].add;
		st[pos].count += st[pos].add*(st[pos].right - st[pos].left + 1) ;          //父节点的count需要更新
		st[pos].add = 0 ;
	}
	int mid = (st[pos].left + st[pos].right)>>1; 
	if(left > mid)
	{
		sum += query(left , right , pos<<1|1);
	}
	else if(right <= mid)
	{
		sum += query(left , right , pos<<1);
	}
	else
	{
		sum += query(left , mid , pos<<1);
		sum += query(mid+1,right , pos<<1|1);
	}
	return sum ;
}


int main()
{
	int n,q;
	while(scanf("%d%d",&n,&q) != EOF)
	{
		char ch;
		int l,r;
		long long data;
		creatTree(1,n,1);
		for(int i = 0 ; i < n ; ++i)
		{
			scanf("%lld",&data);
			init(i+1 , data , 1);
		}
		for(int i = 0 ; i < q ; ++i)
		{
			while(scanf("%c",&ch))
			{
				if(ch != ' ' && ch != '\n')
					break;
			}
			if(ch == 'Q')
			{
				scanf("%d%d",&l,&r);
				printf("%lld\n",query(l,r,1));
			}
			else
			{
				scanf("%d%d%lld",&l,&r,&data);
				update(l,r,data,1);
			}
		}
	}
	return 0;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值