问题描述

有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 = ;
#define max(a,b) a>b?a:b
struct NODE{
int left; //左子树
int right; //右子树
int totalValue; //总和
int maxValue; //最大值
}node[ * 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( * i, left, (left + right) / );
buildTree( * i + , (left + right) / + , right);
node[i].maxValue = node[ * i].maxValue > node[ * i + ].maxValue ? node[ * i].maxValue : node[ * i + ].maxValue;
node[i].totalValue = node[ * i].totalValue + node[ * i + ].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) / )
upDate( * i, x, changedX);
else if (x >= (node[i].left + node[i].right) / )
upDate( * i + , x, changedX);
node[i].maxValue = node[ * i].maxValue > node[ * i + ].maxValue ? node[ * i].maxValue : node[ * i + ].maxValue;
node[i].totalValue = node[ * i].totalValue + node[ * i + ].totalValue;
}
} //查找区间最大值
//i表示node[i]结点,left,right表示查找范围
int findMax(int i, int left, int right){ int maxValue = -;
if (node[i].left == left && node[i].right == right){ //完全重合
maxValue = max(maxValue, node[i].maxValue);
return maxValue;
}
if (left <= node[ * i].right){ //范围跟node[i]的左子树有交集
if (right <= node[ * i].right){
maxValue = max(maxValue, findMax( * i, left, right));
}
else{
maxValue = max(maxValue, findMax( * i, left, node[ * i].right));
}
}
if (right >= node[ * i + ].left){ //范围跟node[i]的右子树有交集
if (left >= node[ * i + ].left){ //被右子树完全包含
maxValue = max(maxValue, findMax( * i + , left, right));
}
else{
maxValue = max(maxValue, findMax( * i + , node[ * i + ].left, right));
}
}
return maxValue;
} //查找区间数值之和
int findTotal(int i, int left, int right){
int total = ;
if (node[i].left == left && node[i].right == right){
total = node[i].totalValue;
return total;
} if (left <= node[ * i].right){
if (right <= node[ * i].right){
total = findTotal( * i, left, right);
}
else{
total += findTotal( * i, left, node[ * i].right);
}
}
if (right >= node[ * i + ].left){
if (left >= node[ * i + ].left){
total = findTotal( * i + , left, right);
}
else{
total += findTotal( * i + , node[ * i + ].left, right);
}
} return total;
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++)
scanf("%d", &nodeValue[i]);
buildTree(, , n); for (int j = ; j <= m; j++){
int workIndex, x, y;
scanf("%d%d%d", &workIndex, &x, &y);
switch (workIndex){
case :
upDate(, x, y);
break;
case :
printf("%d\n", findTotal(, x, y));
break;
case :
printf("%d\n", findMax(, x, y));
break;
}
}

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

AC代码:

#include<stdio.h>
#include<iostream>
using namespace std;
const int MAX_N = ;
#define max(a,b) a>b?a:b
struct NODE{
int left; //左子树
int right; //右子树
int totalValue; //总和
int maxValue; //最大值
}node[ * MAX_N];
int nodeValue[MAX_N]; int maxValue = -;
int totalValue = ;
//建树
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( * i, left, (left + right) / );
buildTree( * i + , (left + right) / + , right);
node[i].maxValue = node[ * i].maxValue > node[ * i + ].maxValue ? node[ * i].maxValue : node[ * i + ].maxValue;
node[i].totalValue = node[ * i].totalValue + node[ * i + ].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) / )
upDate( * i, x, changedX);
else if (x >= (node[i].left + node[i].right) / )
upDate( * i + , x, changedX);
node[i].maxValue = node[ * i].maxValue > node[ * i + ].maxValue ? node[ * i].maxValue : node[ * i + ].maxValue;
node[i].totalValue = node[ * i].totalValue + node[ * i + ].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[ * i].right){ //范围跟node[i]的左子树有交集
if (right <= node[ * i].right){
findMax( * i, left, right);
}
else{
findMax( * i, left, node[ * i].right);
}
}
if (right >= node[ * i + ].left){ //范围跟node[i]的右子树有交集
if (left >= node[ * i + ].left){ //被右子树完全包含
findMax( * i + , left, right);
}
else{
maxValue, findMax( * i + , node[ * i + ].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[ * i].right){
if (right <= node[ * i].right){
findTotal( * i, left, right);
}
else{
findTotal( * i, left, node[ * i].right);
}
}
if (right >= node[ * i + ].left){
if (left >= node[ * i + ].left){
findTotal( * i + , left, right);
}
else{
findTotal( * i + , node[ * i + ].left, right);
}
}
}
int main(){
int n, m;
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++)
scanf("%d", &nodeValue[i]);
buildTree(, , n); for (int j = ; j <= m; j++){
int workIndex, x, y;
scanf("%d%d%d", &workIndex, &x, &y);
switch (workIndex){
case :
upDate(, x, y);
break;
case :
findTotal(, x, y);
printf("%d\n", totalValue);
totalValue = ;
break;
case :
findMax(, x, y);
printf("%d\n", maxValue);
maxValue = -;
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;
*/
}

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

  1. Java实现 蓝桥杯 算法训练 猴子吃包子(暴力)

    试题 算法训练 猴子吃包子 问题描述 从前,有一只吃包子很厉害的猴子,它可以吃无数个包子,但是,它吃不同的包子速度也不同:肉包每秒钟吃x个:韭菜包每秒钟吃y个:没有馅的包子每秒钟吃z个:现在有x1个肉 ...

  2. Java实现蓝桥杯 算法训练 大等于n的最小完全平方数

    试题 算法训练 大等于n的最小完全平方数 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 输出大等于n的最小的完全平方数. 若一个数能表示成某个自然数的平方的形式,则称这个数为完全平 ...

  3. 蓝桥杯算法训练 java算法 表达式求值

    问题描述 输入一个只包含加减乖除和括号的合法表达式,求表达式的值.其中除表示整除. 输入格式 输入一行,包含一个表达式. 输出格式 输出这个表达式的值. 样例输入 1-2+3*(4-5) 样例输出 - ...

  4. 蓝桥杯 算法训练 ALGO-143 字符串变换

    算法训练 字符串变换   时间限制:1.0s   内存限制:256.0MB 问题描述 相信经过这个学期的编程训练,大家对于字符串的操作已经掌握的相当熟练了.今天,徐老师想测试一下大家对于字符串操作的掌 ...

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

    算法训练 王.后传说   时间限制:1.0s   内存限制:256.0MB 问题描述 地球人都知道,在国际象棋中,后如同太阳,光芒四射,威风八面,它能控制横.坚.斜线位置. 看过清宫戏的中国人都知道, ...

  6. Java实现 蓝桥杯 算法训练 Beaver's Calculator

    试题 算法训练 Beaver's Calculator 问题描述 从万能词典来的聪明的海狸已经使我们惊讶了一次.他开发了一种新的计算器,他将此命名为"Beaver's Calculator ...

  7. Java实现 蓝桥杯 算法训练 Lift and Throw

    试题 算法训练 Lift and Throw 问题描述 给定一条标有整点(1, 2, 3, -)的射线. 定义两个点之间的距离为其下标之差的绝对值. Laharl, Etna, Flonne一开始在这 ...

  8. Java实现 蓝桥杯 算法训练 Remember the A La Mode(暴力)

    试题 算法训练 Remember the A La Mode 问题描述 Hugh Samston经营着一个为今年的ICPC世界总决赛的参与者提供甜点的餐饮服务.他将会提供上面有冰激凌的饼片.为了满足不 ...

  9. Java实现 蓝桥杯 算法训练 删除数组零元素

    算法训练 删除数组零元素 时间限制:1.0s 内存限制:512.0MB 提交此题 从键盘读入n个整数放入数组中,编写函数CompactIntegers,删除数组中所有值为0的元素,其后元素向数组首端移 ...

  10. Java实现 蓝桥杯 算法训练 数字游戏

    试题 算法训练 数字游戏 资源限制 时间限制:1.0s 内存限制:256.0MB 问题描述 给定一个1-N的排列a[i],每次将相邻两个数相加,得到新序列,再对新序列重复这样的操作,显然每次得到的序列 ...

随机推荐

  1. 深入浅出数据结构C语言版(21)——合并排序

    在讲解合并排序之前,我们先来想一想这样一个问题如何解决: 有两个数组A和B,它们都已各自按照从小到大的顺序排好了数据,现在我们要把它们合并为一个数组C,且要求C也是按从小到大的顺序排好,请问该怎么做? ...

  2. MySql join on 和 where

    原文:http://www.cnblogs.com/Jessy/p/3525419.html left join :左连接,返回左表中所有的记录以及右表中连接字段相等的记录. right join : ...

  3. MVC发布网站

    首先Vs打开解决方案 在Global.asax中加入下列代码,否则会出现CSS JS失效 BundleTable.EnableOptimizations = false; 用户 'NT AUTHORI ...

  4. How many Knight Placing? UVA - 11091

    How many Knight Placing? Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %l ...

  5. 虚拟机中ubuntu-16.04 Linux系统下配置mysql数据库,并在windows下使用navicat远程连接

    Linux系统下mysql数据库安装配置步骤: 1.在服务器上安装mysql:sudo apt-get install mysql-server sudo apt-get install mysql- ...

  6. WebApi实现验证授权Token,WebApi生成文档等

    using System; using System.Linq; using System.Web; using System.Web.Http; using System.Web.Security; ...

  7. C#解析XML详解(XPath以及带命名空间NameSpace)

    <?xml version="1.0" encoding="utf-8" ?> <bookstore> <book> < ...

  8. NOIP初赛 之 哈夫曼树

    哈夫曼树 种根据我已刷的初赛题中基本每套的倒数第五或第六个不定项选择题就有一个关于哈夫曼树及其各种应用的题,占:0-1.5分:然而我针对这个类型的题也多次不会做,so,今晚好好研究下哈夫曼树: 概念: ...

  9. 3.ElasticSearch的倒排索引

    一. 正向索引 常规的索引建立方式 文档---> 关键词的映射过程(正向索引) 比如: 我有很多个文章,如果想查询其中几个文章是否含有刘耀这个关键词,那么我就需要打开所以文章,找到里面含义刘耀的 ...

  10. WiFi网络WPA2 KRACK漏洞分析报告

    作者:东帆@阿里安全技术平台团队 --------   0x00 漏洞概述 安全研究员Mathy Vanhoef发现的WPA2协议的KRA(Key Reinstallation Attacks)漏洞, ...