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

问题描述

有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

用线段树来解题,一开始的时候结点空间开小了= =

因为N个格子,用线段树的话一共会有2*N-1个结点,所以我不小心就开了2*N-1个结点的空间

结果。。。一半超时。。

修改后发现还是有一个用例超时,上代码:

#include<stdio.h>
#include<iostream>
using namespace std;
const int MAX_N = 100005;
#define max(a,b) a>b?a:b
struct NODE{
    int left;   //左子树
    int right;  //右子树
    int totalValue;  //总和
    int maxValue;     //最大值
}node[10 * MAX_N];
int nodeValue[MAX_N];
//建树
void buildTree(int i, int left, int right){
    node[i].left = left;
    node[i].right = right;
    if (left == right){
        node[i].maxValue = nodeValue[left];
        node[i].totalValue = nodeValue[left];
    }
    else{
        buildTree(2 * i, left, (left + right) / 2);
        buildTree(2 * i + 1, (left + right) / 2 + 1, right);
        node[i].maxValue = node[2 * i].maxValue > node[2 * i + 1].maxValue ? node[2 * i].maxValue : node[2 * i + 1].maxValue;
        node[i].totalValue = node[2 * i].totalValue + node[2 * i + 1].totalValue;
    }
}

//区间更新
void upDate(int i, int x, int changedX){
    if (node[i].left == node[i].right){
        node[i].maxValue = changedX;
        node[i].totalValue = changedX;
    }
    else{
        if (x <= (node[i].left + node[i].right) / 2)
            upDate(2 * i, x, changedX);
        else if (x >= (node[i].left + node[i].right) / 2)
            upDate(2 * i + 1, x, changedX);
        node[i].maxValue = node[2 * i].maxValue > node[2 * i + 1].maxValue ? node[2 * i].maxValue : node[2 * i + 1].maxValue;
        node[i].totalValue = node[2 * i].totalValue + node[2 * i + 1].totalValue;
    }
}

//查找区间最大值
//i表示node[i]结点,left,right表示查找范围
int findMax(int i, int left, int right){

    int maxValue = -1;
    if (node[i].left == left && node[i].right == right){        //完全重合
        maxValue = max(maxValue, node[i].maxValue);
        return maxValue;
    }
    if (left <= node[2 * i].right){         //范围跟node[i]的左子树有交集
        if (right <= node[2 * i].right){
            maxValue = max(maxValue, findMax(2 * i, left, right));
        }
        else{
            maxValue = max(maxValue, findMax(2 * i, left, node[2 * i].right));
        }
    }
    if (right >= node[2 * i + 1].left){          //范围跟node[i]的右子树有交集
        if (left >= node[2 * i + 1].left){     //被右子树完全包含
            maxValue = max(maxValue, findMax(2 * i + 1, left, right));
        }
        else{
            maxValue = max(maxValue, findMax(2 * i + 1, node[2 * i + 1].left, right));
        }
    }
    return maxValue;
}

//查找区间数值之和
int findTotal(int i, int left, int right){
    int total = 0;
    if (node[i].left == left && node[i].right == right){
        total = node[i].totalValue;
        return total;
    }

    if (left <= node[2 * i].right){
        if (right <= node[2 * i].right){
            total = findTotal(2 * i, left, right);
        }
        else{
            total += findTotal(2 * i, left, node[2 * i].right);
        }
    }
    if (right >= node[2 * i + 1].left){
        if (left >= node[2 * i + 1].left){
            total = findTotal(2 * i + 1, left, right);
        }
        else{
            total += findTotal(2 * i + 1, node[2 * i + 1].left, right);
        }
    }

    return total;
}
int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &nodeValue[i]);
    buildTree(1, 1, n);

    for (int j = 1; j <= m; j++){
        int workIndex, x, y;
        scanf("%d%d%d", &workIndex, &x, &y);
        switch (workIndex){
        case 1:
            upDate(1, x, y);
            break;
        case 2:
            printf("%d\n", findTotal(1, x, y));
            break;
        case 3:
            printf("%d\n", findMax(1, x, y));
            break;
        }
    }

然后我修改了一下,不要在每一个查找区间数值方法里面比较最大值和总和,而是在left == right的时候才比较最大值和总和。

AC代码:

#include<stdio.h>
#include<iostream>
using namespace std;
const int MAX_N = 100005;
#define max(a,b) a>b?a:b
struct NODE{
    int left;   //左子树
    int right;  //右子树
    int totalValue;  //总和
    int maxValue;     //最大值
}node[10 * MAX_N];
int nodeValue[MAX_N];

int maxValue = -1;
int totalValue = 0;
//建树
void buildTree(int i, int left, int right){
    node[i].left = left;
    node[i].right = right;
    if (left == right){
        node[i].maxValue = nodeValue[left];
        node[i].totalValue = nodeValue[left];
    }
    else{
        buildTree(2 * i, left, (left + right) / 2);
        buildTree(2 * i + 1, (left + right) / 2 + 1, right);
        node[i].maxValue = node[2 * i].maxValue > node[2 * i + 1].maxValue ? node[2 * i].maxValue : node[2 * i + 1].maxValue;
        node[i].totalValue = node[2 * i].totalValue + node[2 * i + 1].totalValue;
    }
}

//区间更新
void upDate(int i, int x, int changedX){
    if (node[i].left == node[i].right){
        node[i].maxValue = changedX;
        node[i].totalValue = changedX;
    }
    else{
        if (x <= (node[i].left + node[i].right) / 2)
            upDate(2 * i, x, changedX);
        else if (x >= (node[i].left + node[i].right) / 2)
            upDate(2 * i + 1, x, changedX);
        node[i].maxValue = node[2 * i].maxValue > node[2 * i + 1].maxValue ? node[2 * i].maxValue : node[2 * i + 1].maxValue;
        node[i].totalValue = node[2 * i].totalValue + node[2 * i + 1].totalValue;
    }
}

//查找区间最大值
//i表示node[i]结点,left,right表示查找范围
void findMax(int i, int left, int right){

    if (node[i].left == left && node[i].right == right){        //完全重合
        maxValue = max(maxValue, node[i].maxValue);
        return;
    }
    if (left <= node[2 * i].right){         //范围跟node[i]的左子树有交集
        if (right <= node[2 * i].right){
            findMax(2 * i, left, right);
        }
        else{
            findMax(2 * i, left, node[2 * i].right);
        }
    }
    if (right >= node[2 * i + 1].left){          //范围跟node[i]的右子树有交集
        if (left >= node[2 * i + 1].left){     //被右子树完全包含
            findMax(2 * i + 1, left, right);
        }
        else{
            maxValue, findMax(2 * i + 1, node[2 * i + 1].left, right);
        }
    }
}

//查找区间数值之和
void findTotal(int i, int left, int right){
    if (node[i].left == left && node[i].right == right){
        totalValue += node[i].totalValue;
        return;
    }

    if (left <= node[2 * i].right){
        if (right <= node[2 * i].right){
            findTotal(2 * i, left, right);
        }
        else{
            findTotal(2 * i, left, node[2 * i].right);
        }
    }
    if (right >= node[2 * i + 1].left){
        if (left >= node[2 * i + 1].left){
            findTotal(2 * i + 1, left, right);
        }
        else{
            findTotal(2 * i + 1, node[2 * i + 1].left, right);
        }
    }
}
int main(){
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &nodeValue[i]);
    buildTree(1, 1, n);

    for (int j = 1; j <= m; j++){
        int workIndex, x, y;
        scanf("%d%d%d", &workIndex, &x, &y);
        switch (workIndex){
        case 1:
            upDate(1, x, y);
            break;
        case 2:
            findTotal(1, x, y);
            printf("%d\n", totalValue);
            totalValue = 0;
            break;
        case 3:
            findMax(1, x, y);
            printf("%d\n", maxValue);
            maxValue = -1;
            break;
        }
    }

    /*
    for(int j = 1;j<=2*n-1;j++){
    cout<<"left: "<<node[j].left<<endl;
    cout<<"right: "<<node[j].right<<endl;
    cout<<"maxValue: "<<node[j].maxValue<<endl;
    cout<<"totalValue: "<<node[j].totalValue<<endl;
    }
    */
    /*
    cout<<"1 到 4号格子最大值: "<<findMax(1,1,4)<<endl;
    cout<<"1 到 2号格子最大值: "<<findMax(1,1,2)<<endl;
    cout<<"1 到 3号格子最大值: "<<findMax(1,1,3)<<endl;
    cout<<"2 到 4号格子最大值: "<<findMax(1,2,4)<<endl;
    cout<<"2 到 3号格子最大值: "<<findMax(1,2,3)<<endl;
    cout<<"3 到 4号格子最大值: "<<findMax(1,3,4)<<endl;

    cout<<"1 到 4号格子权值和: "<<findTotal(1,1,4)<<endl;
    cout<<"1 到 2号格子权值和: "<<findTotal(1,1,2)<<endl;
    cout<<"1 到 3号格子权值和: "<<findTotal(1,1,3)<<endl;
    cout<<"2 到 4号格子权值和: "<<findTotal(1,2,4)<<endl;
    cout<<"2 到 3号格子权值和: "<<findTotal(1,2,3)<<endl;
    cout<<"3 到 4号格子权值和: "<<findTotal(1,3,4)<<endl;
    */
}
时间: 2024-10-05 09:44:32

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

蓝桥杯——算法训练之乘积最大

问题描述 今年是国际数学联盟确定的"2000--世界数学年",又恰逢我国著名数学家华罗庚先生诞辰90周年.在华罗庚先生的家乡江苏金坛,组织了一场别开生面的数学智力竞赛的活动,你的一个好朋友XZ也有幸得以参加.活动中,主持人给所有参加活动的选手出了这样一道题目: 设有一个长度为N的数字串,要求选手使用K个乘号将它分成K+1个部分,找出一种分法,使得这K+1个部分的乘积能够为最大. 同时,为了帮助选手能够正确理解题意,主持人还举了如下的一个例子: 有一个数字串:312, 当N=3,K=1时

蓝桥杯 算法训练 操作格子 [ 线段树 ]

传送门 算法训练 操作格子 时间限制:1.0s   内存限制:256.0MB 锦囊1 锦囊2 锦囊3 问题描述 有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

蓝桥杯 算法训练 ALGO-125 王、后传说

算法训练 王.后传说 时间限制:1.0s   内存限制:256.0MB 问题描述 地球人都知道,在国际象棋中,后如同太阳,光芒四射,威风八面,它能控制横.坚.斜线位置. 看过清宫戏的中国人都知道,后宫乃步步惊心的险恶之地.各皇后都有自己的势力范围,但也总能找到相安无事的办法. 所有中国人都知道,皇权神圣,伴君如伴虎,触龙颜者死...... 现在有一个n*n的皇宫,国王占据他所在位置及周围的共9个格子,这些格子皇后不能使用(如果国王在王宫的边上,占用的格子可能不到9个).当然,皇后也不会攻击国王.

蓝桥杯--算法训练

<1>区间k大数查询 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正整数,表示给定的序列. 第三个包含一个正整数m,表示询问个数. 接下来m行,每行三个数l,r,K,表示询问序列从左往右第l个数到第r个数中,从大往小第K大的数是哪个.序列元素从1开始标号. 输出格式 总共输出m行,每行一个数,表示询问的答案. 样例输入 51 2 3 4 521 5 22 3 2 样例输出 42 数据规模与约定 对于3

蓝桥杯 算法训练 ALGO-124 数字三角形

算法训练 数字三角形 时间限制:1.0s   内存限制:256.0MB 问题描述 (图3.1-1)示出了一个数字三角形. 请编一个程序计算从顶至底的某处的一条路 径,使该路径所经过的数字的总和最大. ●每一步可沿左斜线向下或右斜线向下走: ●1<三角形行数≤100: ●三角形中的数字为整数0,1,-99: . (图3.1-1) 输入格式 文件中首先读到的是三角形的行数. 接下来描述整个三角形 输出格式 最大总和(整数) 样例输入 573 88 1 02 7 4 44 5 2 6 5 样例输出 3

蓝桥杯 算法训练 ALGO-139 s01串

算法训练 s01串 时间限制:1.0s 内存限制:256.0MB 问题描述  s01串初始为"0"  按以下方式变换  0变1,1变01 输入格式  1个整数(0~19) 输出格式  n次变换后s01串 样例输入 3 样例输出 101 数据规模和约定  0~19 示例代码: 1 import java.util.Scanner; 2 3 public class Main { 4 static StringBuffer sb = new StringBuffer(); 5 public

蓝桥杯 算法训练 2的次幂表示

算法训练 2的次幂表示 时间限制:1.0s   内存限制:512.0MB 问题描述 任何一个正整数都可以用2进制表示,例如:137的2进制表示为10001001. 将这种2进制表示写成2的次幂的和的形式,令次幂高的排在前面,可得到如下表达式:137=2^7+2^3+2^0 现在约定幂次用括号来表示,即a^b表示为a(b) 此时,137可表示为:2(7)+2(3)+2(0) 进一步:7=2^2+2+2^0 (2^1用2表示) 3=2+2^0  所以最后137可表示为:2(2(2)+2+2(0))+

蓝桥杯 算法训练 最短路

算法训练 最短路 时间限制:1.0s   内存限制:256.0MB 问题描述 给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环).请你计算从1号点到其他点的最短路(顶点从1到n编号). 输入格式 第一行两个整数n, m. 接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边. 输出格式 共n-1行,第i行表示1号点到i+1号点的最短路. 样例输入 3 31 2 -12 3 -13 1 2 样例输出 -1-2 数据规模与约定 对于10%的数据,n = 2,

蓝桥杯 算法训练 ALGO-57 删除多余括号

算法训练 删除多余括号 时间限制:1.0s   内存限制:512.0MB 问题描述 从键盘输入一个含有括号的四则运算表达式,要求去掉可能含有的多余的括号,结果要保持原表达式中变量和运算符的相对位置不变,且与原表达式等价,不要求化简.另外不考虑'+' '-'用作正负号的情况,即输入表达式不会出现(+a)或(-a)的情形. 输入格式 表达式字符串,长度不超过255, 并且不含空格字符.表达式中的所有变量都是单个小写的英文字母, 运算符只有加+减-乘*除/等运算符号. 输出格式 去掉多余括号后的表达式

蓝桥杯 算法训练 ALGO-117 友好数

算法训练 友好数 时间限制:1.0s   内存限制:256.0MB 问题描述 有两个整数,如果每个整数的约数和(除了它本身以外)等于对方,我们就称这对数是友好的.例如: 9的约数和有:1+3=4 4的约数和有:1+2=3 所以9和4不是友好的. 220的约数和有:1 2 4 5 10 11 20 22 44 55 110=284 284的约数和有:1 2 4 71 142=220 所以220和284是友好的. 编写程序,判断两个数是否是友好数. 输入格式 一行,两个整数,由空格分隔 输出格式 如