#180-[线段树]乘积

Description

      给定一个序列,你的任务是随时告诉他某段区间所有数的乘积,当然,他可不会给出一个这么简单的问题,为了让问题更有(e)趣(xin),他不时会修改其中某个元素的值。
 

Input

第1行,两个正整数n,m。
第2行,n个正整数,表示数列中元素的初值。
第3至m+2行,每行三个正整数p,x,y。
当p=1表示查询x到y区间内的数的乘积;
当p=2表示修改第x个数为y。

 

Output

对于每个询问输出一行,表示询问结果(模10^9+7)。

 

3 3
2 2 2
1 1 3
2 2 3
1 2 3
  • Sample Input

8
6
  • Sample Output

HINT

【数据规模】
对于30%的数据,满足1<=n,m<=1000;
对于100%的数据,满足1<=n,m<=100000,输入数据保证没有错误,且序列中的元素在任意时刻都不会超过100000。

很明显,线段树模板

#include 
#include 

#define SIZE 400010
#define MOD (int (1e+09 + 7))

using namespace std;

typedef long long long_long; // 解决强制转换得到CE的某小bug

int res[SIZE];

void buildtree(int pos, int l, int r) // 建树
{
	int mid;
	
	if (l == r)
	{
		scanf("%d", &res[pos]);
		return;
	}
	mid = l + r >> 1;
	buildtree(pos << 1, l, mid);
	buildtree((pos << 1) | 1, mid + 1, r);
	res[pos] = (long_long (res[pos<<1]) * long_long (res[(pos<<1)+1])) % MOD; // 要强制转换!不然int溢出.
	
	return;
}

void update(int pos, int l, int r, int x, int y) // 更新一个数
{
	int mid;
	
	if (l == r)
	{
		res[pos] = y;
		return;
	}
	mid = l + r >> 1;
	if (x <= mid)
	{
		update(pos << 1, l, mid, x, y);
	}
	else
	{
		update((pos << 1) | 1, mid + 1, r, x, y);
	}
	res[pos] = (long_long (res[pos<<1]) * long_long (res[(pos<<1)|1])) % MOD;
	
	return;
}

int query(int pos, int l, int r, int x, int y) // 询问区间乘积
{
	int t1, t2, mid;
	
	if ((x <= l) && (y >= r))
	{
		return res[pos];
	}
	mid = l + r >> 1;
	t1 = t2 = 1;
	if (x <= mid)
	{
		t1 = query(pos << 1, l, mid, x, y);
	}
	if (y > mid)
	{
		t2 = query((pos << 1) | 1, mid + 1, r, x, y);
	}
	
	return (long_long (t1) * long_long (t2)) % MOD;
}

int main(void)
{
	int n, m, p, x, y;
	
	scanf("%d%d", &n, &m);
	buildtree(1, 1, n);
	while (m--)
	{
		scanf("%d%d%d", &p, &x, &y); // 操作编号和参数
		if (p == 1)
		{
			printf("%d\n", query(1, 1, n, x, y));
		}
		else
		{
			update(1, 1, n, x, y);
		}
	}
	
	return 0;
}

 

你可能感兴趣的:(刷题,gdgzoi刷题)