蓝桥杯-算法训练 操作格子

算法训练 操作格子  
时间限制:1.0s   内存限制:256.0MB
      
问题描述
有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。

此题考察了线段树的构造与使用,下图就是线段树的概念图:

                                                      【1,10】

                        【1,5】                                                             【6,10】

           【1,3】             【4,5】                                    【6,8】           【9,10】

    【1,2】 【3,3】 【4,4】  【5,5】               【6,7】  【8,8】  【9,9】  【10,10】

【1,1】【2,2】                                           【6,6】【7,7】

超时代码:(用数组的一般方法一定会超时,计算100000个数组的和需要较多时间)

#include<stdio.h>
int a[100010];
void Fun1(int x,int y,int a[]){
    a[x]=y;
}
int Fun2(int x,int y,int a[]){
    int i,sum=0;
    for(i=x;i<=y;i++)
    sum+=a[i];
    return sum;
}
int Fun3(int x,int y,int a[]){
    int i,max=-999999;
    for(i=x;i<=y;i++)
    if(a[i]>max)
    max=a[i];
    return max;
}
int main()
{
    int i,n,m,p,x,y;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    scanf("%d",&a[i]);
    while(m--)
    {
       scanf("%d%d%d",&p,&x,&y);
       if(p==1){
         Fun1(x,y,a);
       }else if(p==2){
         printf("%d\n",Fun2(x,y,a));
       }else{
         printf("%d\n",Fun3(x,y,a));
       }
    }
    return 0;
}

    
AC代码:(采用线段树)

#include<stdio.h>
int Testmax(int a,int b)//判断大小的函数
{return a>b?a:b;}
typedef struct node//构造一个线段树的结构体
{
   int l,r;
   int sum,max;
}node;
node a[400010];//申请线段树节点空间
void Build(int n,int l,int r);//构建一棵范围在l至r范围的线段树
void Insert(int n, int v, int num);//为线段树插入一个值
void Change(int n, int v, int num);//为线段树改变一个权值
int QSum(int n, int l, int r);//求一个范围内的权值总和
int QMax(int n, int l, int r);//求一个范围内的最大值
int main()
{
    int i,j,n,m,value,que,b,c;
    scanf("%d%d",&n,&m);
    Build(1,1,n);//构建一个范围为1至n的线段树
    for(i=1;i<=n;i++)
    {
       scanf("%d",&value);
       Insert(1,i,value);//向已有线段树中插入权值
    }
    while(m--)
    {
      scanf("%d%d%d",&que,&b,&c);
      switch(que)
      {
         case 1:Change(1,b,c);break;//改变节点b的权值为c
         case 2:printf("%d\n", QSum(1,b,c));break;//计算b至c范围内的权值和
         case 3:printf("%d\n", QMax(1,b,c));break;//计算b至c范围内的最大权值
      }
    }
    return 0;
}
void Build(int n,int l,int r)//构建一棵范围在l至r范围的线段树
{
     a[n].l=l;//左边距
     a[n].r=r;//右边距
     a[n].sum=0;//范围在l至r之间权值和
     a[n].max=0;//范围在l至r之间权值最大值
     if(l==r)//如果左右边距相同不再构建孩子
     return;
     Build(n*2,l,(l+r)/2);//构建范围为l至(l+r)/2的左孩子
     Build(n*2+1,(l+r)/2+1,r);//构建范围为l至(l+r)/2的右孩子
}
void Insert(int n, int v, int num)//为线段树插入一个值
{
    a[n].sum += num;//总和加入新数
    if(a[n].max < num)
    a[n].max = num;//更新最大值
    if(a[n].l == a[n].r)//左右边距相等不再插入更新
    return;
    if(v <= (a[n].l + a[n].r) / 2)
    Insert(n*2, v, num);//更新左孩子
    else
    Insert(n*2+1, v, num);//更新右孩子
}
void Change(int n, int v, int num)//为线段树改变一个权值
{
    if(v == a[n].l && v == a[n].r)//下标与左右范围相等 ,存本数
    {
        a[n].sum = num;
        a[n].max = num;
        return;
    }
    int middle = (a[n].l + a[n].r) / 2;
    if(v <= middle)
    Change(n*2, v, num);//更改左孩子
    else
    Change(n*2+1, v, num);//更改右孩子
    a[n].sum = a[n*2].sum + a[n*2+1].sum;//更新总和
    a[n].max = Testmax(a[n*2].max,a[n*2+1].max);//更新最大值
}
int QSum(int n, int l, int r)//求一个范围内的权值总和
{
    if(l == a[n].l && r == a[n].r)//所求范围与左右范围相等 ,直接输出总和
    return a[n].sum;
    int middle = (a[n].l + a[n].r) / 2;
    if(r <= middle)
    return QSum(n*2, l, r);//若所求范围在左孩子范围内,从左孩子寻找
    else if(l > middle)
    return QSum(n*2+1, l, r);//若所求范围在右孩子范围内,从右孩子寻找
    else return QSum(n*2,l,middle) + QSum(n*2+1,middle+1,r);//若范围在左右孩子之间,分别求总和
}
int QMax(int n, int l, int r)//计算b至c范围内的最大权值
{
    if(l == a[n].l && r == a[n].r)//所求范围与左右范围相等 ,直接输出最大值
    return a[n].max;
    int middle = (a[n].l + a[n].r) / 2;
    if(r <= middle)
    return QMax(n*2, l, r);//若所求范围在左孩子范围内,从左孩子寻找
    else if(l > middle)
    return QMax(n*2+1, l, r);//若所求范围在右孩子范围内,从右孩子寻找
    else
    return Testmax(QMax(n*2, l, middle), QMax(n*2+1, middle+1, r));//若范围在左右孩子之间,分别求最大值,然后求最终最大值
}
时间: 2024-12-22 05:37:28

蓝桥杯-算法训练 操作格子的相关文章

蓝桥杯-算法训练2 最大最小公倍数

刚做了,蓝桥杯算法训练的最大最小公倍数一题,感觉考查的是数学了,哈哈. 时间限制:1.0s   内存限制:256.0MB 问题描述 已知一个正整数N,问从1~N中任选出三个数,他们的最小公倍数最大可以为多少. 输入格式 输入一个正整数N. 输出格式 输出一个整数,表示你找到的最小公倍数. 样例输入 9 样例输出 504 数据规模与约定 1 <= N <= 10^6. 思路如下: 1. n是奇数,那就最大的三个数相乘 2. n是偶数,得分两种情况了, ①如果n不是3的倍数,那就s=n*(n-1)

蓝桥杯 算法训练 安慰奶牛

 算法训练 安慰奶牛   时间限制:1.0s   内存限制:256.0M 问题描述 Farmer John变得非常懒,他不想再继续维护供奶牛之间供通行的道路.道路被用来连接N个牧场,牧场被连续地编号为1到N.每一个牧场都是一个奶牛的家.FJ计划除去P条道路中尽可能多的道路,但是还要保持牧场之间 的连通性.你首先要决定那些道路是需要保留的N-1条道路.第j条双向道路连接了牧场Sj和Ej(1 <= Sj <= N; 1 <= Ej <= N; Sj != Ej),而且走完它需要Lj的时

蓝桥杯-算法训练51-Torry的困惑(基本型)

今天做这道题最初以为会用到什么数学公式,在思考后发现自己想多了. 思路主要两个: 1. 生成一个质数表,再按要求求值(本文就按此方法): 2.从小取到大,判断是否是质数,如果是就相乘,并构建计数器判断是否达到n个. 算法训练 Torry的困惑(基本型)   时间限制:1.0s   内存限制:512.0MB 问题描述 Torry从小喜爱数学.一天,老师告诉他,像2.3.5.7--这样的数叫做质数.Torry突然想到一个问题,前10.100.1000.10000--个质数的乘积是多少呢?他把这个问题

lift and throw-蓝桥杯-算法训练 Lift and Throw 求教各位大牛,谢谢各位

问题描述 蓝桥杯-算法训练 Lift and Throw 求教各位大牛,谢谢各位 问题描述 给定一条标有整点(1, 2, 3, ...)的射线. 定义两个点之间的距离为其下标之差的绝对值. Laharl, Etna, Flonne一开始在这条射线上不同的三个点, 他们希望其中某个人能够到达下标最大的点. 每个角色只能进行下面的3种操作, 且每种操作每人不能进行超过一次. 1.移动一定的距离 2.把另一个角色高举过头 3.将举在头上的角色扔出一段距离 每个角色有一个movement range参数

蓝桥杯 算法问题 求解

问题描述 蓝桥杯 算法问题 求解 问题描述 给定一条标有整点(1, 2, 3, ...)的射线. 定义两个点之间的距离为其下标之差的绝对值. Laharl, Etna, Flonne一开始在这条射线上不同的三个点, 他们希望其中某个人能够到达下标最大的点. 每个角色只能进行下面的3种操作, 且每种操作不能每人不能进行超过一次. 1.移动一定的距离 2.把另一个角色高举过头 3.将举在头上的角色扔出一段距离 每个角色有一个movement range参数, 他们只能移动到没有人的位置, 并且起点和

蓝桥杯 算法提高 日期计算

  算法提高 日期计算  时间限制:1.0s   内存限制:256.0MB       问题描述 已知2011年11月11日是星期五,问YYYY年MM月DD日是星期几?注意考虑闰年的情况.尤其是逢百年不闰,逢400年闰的情况. 输入格式 输入只有一行 YYYY MM DD 输出格式 输出只有一行 W 数据规模和约定 1599 <= YYYY <= 2999 1 <= MM <= 12 1 <= DD <= 31,且确保测试样例中YYYY年MM月DD日是一个合理日期 1

蓝桥杯-历届试题 剪格子

历届试题 剪格子   时间限制:1.0s   内存限制:256.0MB        问题描述 如下图所示,3 x 3 的格子中填写了一些整数. +--*--+--+ |10* 1|52| +--****--+ |20|30* 1| *******--+ | 1| 2| 3| +--+--+--+ 我们沿着图中的星号线剪开,得到两个部分,每个部分的数字和都是60. 本题的要求就是请你编程判定:对给定的m x n 的格子中的整数,是否可以分割为两个部分,使得这两个区域的数字和相等. 如果存在多种解

java-蓝桥杯算法提高 最大值问题

问题描述 蓝桥杯算法提高 最大值问题 问题描述 给n个有序整数对ai bi,你需要选择一些整数对 使得所有你选定的数的ai+bi的和最大.并且要求你选定的数对的ai之和非负,bi之和非负. 输入格式 输入的第一行为n,数对的个数 以下n行每行两个整数 ai bi 输出格式 输出你选定的数对的ai+bi之和 样例输入 5 -403 -625 -847 901 -624 -708 -293 413 886 709 样例输出 1715 数据规模和约定 1<=n<=100 -1000<=ai,b

蓝桥杯 java 操作格子-操作格子蓝桥杯java线段树也超限怎么办

问题描述 操作格子蓝桥杯java线段树也超限怎么办 如题: 问题描述 有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