问题描述
有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
1 2 3 4
2 1 3
1 4 3
3 1 4
样例输出
6
3
3
1 <= n <= 100000,m <= 100000,0 <= 格子权值 <= 10000
思路:线段树裸题,点更新区间查询.
代码:
#include<map>
#include<cstdio>
#include<vector>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
using namespace std;
struct tree
{
int l,r;
int maxx;
long long sum;
}t[400005];
int n,m;
int a[100005];
void build(int i,int l,int r)//建树
{
t[i].l = l;//管辖范围
t[i].r = r;
if(l == r)//底部赋值
{
t[i].maxx = a[l];
t[i].sum = a[l];
return ;
}
int mid = (l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
t[i].maxx = max(t[i<<1].maxx,t[i<<1|1].maxx);//管辖范围内最大值
t[i].sum = t[i<<1].sum+t[i<<1|1].sum;//管辖范围总和
}
void mod(int i,int x,int val)//点更新
{
if(x>t[i].r||x<t[i].l)//不在范围内
return ;
if(t[i].l == t[i].r)//找到了
{
t[i].sum = val;
t[i].maxx = val;
return ;
}
mod(i<<1,x,val);
mod(i<<1|1,x,val);
t[i].maxx = max(t[i<<1].maxx,t[i<<1|1].maxx);//更新
t[i].sum = t[i<<1].sum+t[i<<1|1].sum;
}
long long query_sum(int i,int a,int b)//求区间总和
{
if(a>t[i].r||b<t[i].l)//不在范围内
return 0;
if(t[i].l>= a&&t[i].r<= b)//寻找范围完全包含 管辖范围
return t[i].sum;
return query_sum(i<<1,a,b)+query_sum(i<<1|1,a,b);
}
int query_max(int i,int a,int b)//求区间最大值
{
if(a>t[i].r||b<t[i].l)
return 0;
if(t[i].l>= a&&t[i].r<= b)
return t[i].maxx;
return max(query_max(i<<1,a,b),query_max(i<<1|1,a,b));
}
int main()
{
memset(t,0,sizeof(t));
cin>>n>>m;
for(int i = 1;i<= n;i++)
scanf("%d",&a[i]);
build(1,1,n);
while(m--)
{
int o,a,b;
scanf("%d %d %d",&o,&a,&b);
if(o == 1)
mod(1,a,b);
else if(o == 2)
{
long long ans = query_sum(1,a,b);
printf("%I64d\n",ans);
}
else if(o == 3)
{
int ans = query_max(1,a,b);
printf("%d\n",ans);
}
}
return 0;
}