您的位置:首页 > 其它

蓝桥杯 操作格子(线段树)

2018-03-10 11:40 246 查看
问题描述有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
31 <= 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  蓝桥杯 线段树