试题 算法训练 操作格子(暴力解法和线段树解法)

问题描述
有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操作的结果。

解题思路
暴力求解!!!
直接求和,求最大值!!!

代码

#include 
int arr[100000];
int sum(int x,int y)
{
    int sum=0;
    for(int i=x;i<=y;i++)
    {
        sum+=arr[i];
    }
    return sum;
}

int Max(int x,int y)
{
    int res=arr[x];
    for(int i=x;i<=y;i++)
    {
        if(arr[i]>res)res=arr[i];
    }
    return res;
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&arr[i]);
    }
    for(int i=1;i<=m;i++)
    {
        int command,para1,para2;
        scanf("%d%d%d",&command,&para1,&para2);
        if(command==1)arr[para1]=para2;
        if(command==2)
        {
            printf("%d\n",sum(para1,para2));
        }
        if(command==3)
        {
            printf("%d\n",Max(para1,para2));
        }
    }
    return 0;
}

运行结果
竟然过了,过了。。。。
在这里插入图片描述
我惊呆了,题目上不是说要用线段树吗,暴力求解竟然能过。。。
在这里插入图片描述
不过,暴力不是我做这道题目的目的,还是去学习一下线段树吧!毕竟不是所有的测试系统都会对菜鸡这么友好。

线段树求解

线段树基础知识详解,强烈推荐!!!!
https://blog.csdn.net/huangzihaoal/article/details/81813454
(点击那句话也可以进入链接,这个博主讲的非常详细。)

线段树空间开辟的注意点线段树的大小其实是4n左右的。
不然,最后测试用例上会因为索引越界而出现运行超时的错误,一定要注意!!!!

线段树求解代码

#include 

struct node
{
    int l,r,sum,Max,lazy;
    node(){l=r=sum=Max=lazy=0;}
}a[400000];
int number[400000];//这里一定要是4n!!!

int Max(int a,int b){return a>b?a:b;}

inline void update(int k)//更新节点状态
{
    a[k].sum=a[k*2].sum+a[k*2+1].sum;
    a[k].Max=Max(a[k*2].Max,a[k*2+1].Max);
}

void build(int k,int l,int r)//建树
{
    a[k].l=l,a[k].r=r;
    if(l==r)
    {
        a[k].sum=number[l];
        a[k].Max=number[l];
        return;
    }
    int mid=(l+r)/2;
    build(k*2,l,mid);
    build(k*2+1,mid+1,r);
    update(k);
}

void change(int k,int x,int y)//改变节点
{
    if(a[k].l==a[k].r){a[k].sum=y;a[k].Max=y;return;}
    int mid=(a[k].l+a[k].r)/2;
    if(x<=mid) change(k*2,x,y);
    else change(k*2+1,x,y);
    update(k);
}

int query(int k,int l,int r)//查询区间求和的值
{
    if(a[k].l==l&&a[k].r==r) return a[k].sum;
    int mid=(a[k].l+a[k].r)/2;
    if(r<=mid)return query(k*2,l,r);
    if(l>mid)return query(k*2+1,l,r);
    return query(k*2,l,mid)+query(k*2+1,mid+1,r);
}

int queryMax(int k,int l,int r)//查询区间最大值
{
    if(a[k].l==l&&a[k].r==r) return a[k].Max;
    int mid=(a[k].l+a[k].r)/2;
    if(r<=mid)return queryMax(k*2,l,r);
    if(l>mid)return queryMax(k*2+1,l,r);
    return Max(queryMax(k*2,l,mid),queryMax(k*2+1,mid+1,r));
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&number[i]);
    }
    build(1,1,n);
    for(int i=1;i<=m;i++)
    {
        int command,para1,para2;
        scanf("%d%d%d",&command,&para1,&para2);
        if(command==1)
        {
            change(1,para1,para2);
        }
        if(command==2)
        {
            printf("%d\n",query(1,para1,para2));
        }
        if(command==3)
        {
            printf("%d\n",queryMax(1,para1,para2));
        }
    }
    return 0;
}

运行结果
在这里插入图片描述

果然比暴力解法节省了不少的时间,算法真的神奇!!!

你可能感兴趣的:(蓝桥杯省赛备战,算法)