蓝桥杯练习-操作格子【树状数组】

问题描述

有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。


我是用树状数组做的。

#include <stdio.h>
#include <string.h>
#define Max(a,b) a>b?a:b
#define Maxn 100010
int v[Maxn];
int sum[Maxn];
int max[Maxn];
int n;
int lowbit(int x)
{
	return x&(-x);
}
void upDate(int x,int num)
{
	while(x<=n)
	{
		sum[x]+=num;
		max[x]=Max(max[x],num);
		x+=lowbit(x);
	}
}
int getSum(int x)
{
	int res=0;
	while(x>0)
	{
		res+=sum[x];
		x-=lowbit(x);
	}
	return res;
}
int getMax(int x,int y)
{
	int t=0;
	for(int i=y;i>=x;)
	{
		if(i-lowbit(i)+1>=x)
			{t=Max(t,max[i]);i-=lowbit(i);}
		else {t=Max(t,v[i]);i--;}
	}
	return t;
}
void retreat(int x,int num)
{
	int t=v[x];
	int i=x;
	v[x]=num;
	while(i<=n)
	{
		sum[i]-=t;
		sum[i]+=num;
		i+=lowbit(i);
	}
	i=x;
	while(i<=n)
	{
		if(max[i]==t)
		{
			max[i]=Max(getMax(i-lowbit(i)+1,i-1),num);
			max[i]=Max(v[i],max[i]);
		}
		else break;
		i+=lowbit(i);
	}
	i=x;
	while(i<=n)
	{
		max[i]=Max(max[i],num);
		i+=lowbit(i);
	}
}
int main()
{
	int m;
	int i,j;
	while(~scanf("%d%d",&n,&m))
	{
		memset(sum,0,sizeof(sum));
		memset(max,0,sizeof(max));
		for(i=1;i<=n;i++)
		{
			scanf("%d",&v[i]);
			upDate(i,v[i]);
		}
		for(j=1;j<=m;j++)
		{
			int a,b,c;
			scanf("%d %d %d",&a,&b,&c);
			if(a==1)
			{
				retreat(b,c);
			}
			else if(a==2)
			{
				printf("%d\n",getSum(c)-getSum(b-1));
			}
			else printf("%d\n",getMax(b,c));
		}
	}
	return 0;
}


你可能感兴趣的:(蓝桥杯练习-操作格子【树状数组】)