操作格子(线段树)

操作格子
问题描述

有n个格子,从左到右放成一排,编号为1-n。

共有m次操作,有3种操作类型:

1.修改一个格子的权值,

2.求连续一段格子权值和,

3.求连续一段格子的最大值。

对于每个2、3操作输出你所求出的结果。

输入格式

第一行2个整数n,m。

接下来一行n个整数表示n个格子的初始权值。

接下来m行,每行3个整数p,x,y,p表示操作类型,p=1时表示修改格子x的权值为y,p=2时表示求区间[x,y]内格子权值和,p=3时表示求区间[x,y]内格子最大的权值。

输出格式

有若干行,行数等于p=2或3的操作总数。

每行1个整数,对应了每个p=2或3操作的结果。

样例输入
4 3
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
数据规模与约定

对于20%的数据n <= 100,m <= 200。

对于50%的数据n <= 5000,m <= 5000。

对于100%的数据1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000。

题意很明确,更新点,求区间和and区间最大值,用线段树很好就求出来。

注意:线段树的大小应该是maxn * 4;如果开小就会提示运行超时。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define inf 0x3f3f3f3f
using namespace std;

const int maxn = 100010;
int n, m;

struct node{
	int gl, gr, gsum, gmax;
};
node a[maxn * 4];

void init(int l, int r, int num)
{
	a[num].gl = l;
	a[num].gr = r;
	a[num].gmax = 0;
	a[num].gsum = 0;
	if(l >= r)
		return;
	int mid = (l + r) >> 1;
	init(l, mid, num << 1);
	init(mid + 1, r, num << 1 | 1);
}

void insert(int num, int i, int x)
{
	if(i < a[num].gl || i > a[num].gr)
		return;
	if(a[num].gl == a[num].gr)
	{
		if(i == a[num].gl)
		{
			a[num].gmax = x;
			a[num].gsum = x;
		}
		return;
	}
	int mid = (a[num].gl + a[num].gr) >> 1;
	if(i <= mid)
		insert(num << 1, i, x);
	else 
		insert(num << 1 | 1, i, x);
	a[num].gmax = max(a[num << 1].gmax, a[num <<1 | 1].gmax);
	a[num].gsum = a[num << 1].gsum +a[num << 1 | 1].gsum;
}

int getsum(int num, int l, int r)
{
	if(l <= a[num].gl && r >= a[num].gr)
		return a[num].gsum;
	if(l > a[num].gr || r < a[num].gl)
		return 0;
	int mid = (a[num].gl + a[num].gr) >> 1;
	if(l > mid)
		return getsum(num << 1 | 1, l, r);
	else if(r <= mid)
		return getsum(num << 1, l, r);
	else
		return getsum(num << 1, l, mid) + getsum(num << 1 | 1, mid + 1, r);
}

int getmax(int num, int l, int r)
{
	if(l == a[num].gl && r == a[num].gr)
		return a[num].gmax;
	if(l > a[num].gr || r < a[num].gl)
		return 0;
	int mid = (a[num].gl + a[num].gr) >> 1;
	if(l > mid)
		return getmax(num << 1 | 1, l, r);
	else if(r <= mid)
		return getmax(num << 1, l,  r);
	else
		return max(getmax(num << 1, l, mid) , getmax(num << 1 | 1, mid + 1, r));
}
int main()
{
	int cas, x, y;
	scanf("%d%d", &n, &m);
	init(1, n, 1);
	for(int i = 1; i <= n; i++)
	{
		scanf("%d", &x);
		insert(1, i, x);
	}
	for(int i = 0; i < m; i++)
	{
		scanf("%d%d%d", &cas, &x, &y);
		if(cas == 1)
			insert(1, x, y);
		else if(cas == 2)
			printf("%d\n", getsum(1, x, y));
		else
			printf("%d\n", getmax(1, x, y));
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值