博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
最高分是多少
阅读量:7041 次
发布时间:2019-06-28

本文共 3693 字,大约阅读时间需要 12 分钟。

最高分是多少

题目描述

老师想知道从某某同学当中,分数最高的是多少,现在请你编程模拟老师的询问。当然,老师有时候需要更新某位同学的成绩.

输入描述:

输入包括多组测试数据。每组输入第一行是两个正整数N和M(0 < N <= 30000,0 < M < 5000),分别代表学生的数目和操作的数目。学生ID编号从1编到N。第二行包含N个整数,代表这N个学生的初始成绩,其中第i个数代表ID为i的学生的成绩接下来又M行,每一行有一个字符C(只取‘Q’或‘U’),和两个正整数A,B,当C为'Q'的时候, 表示这是一条询问操作,他询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少当C为‘U’的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。

输出描述:

对于每一次询问操作,在一行里面输出最高成绩.
示例1

输入

5 71 2 3 4 5Q 1 5U 3 6Q 3 4Q 4 5U 4 5U 2 9Q 1 5

输出

5659

 

分析:

这个题目树状数组线段树都是OK的,但是没有涉及到对区间的操作,树状数组在时间和空间上面的代价都要小很多。

 

 

牛客网题解:

暴力,线段树,块状链表

链接:

来源:牛客网

华为仿佛找了一种比较奇特的方法来区分应聘者啊。
先来说说这题的3种做法:
最简单的就是暴力了。每次查询直接做。
修改复杂度O(1),查询复杂度O(N)
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <stdio.h>
#include <algorithm>
using
namespace
std;
 
const
int
MAXN=100000;
 
int
data[MAXN+5];
 
int
querymax (
int
l ,
int
r ) {
    
int
ans=data[l];
    
for
(
int
i=l+1;i<=r;i++) ans=max(ans,data[i]);
    
return
ans;
}
 
void
update(
int
idx,
int
value){
    
data[idx]=value;
}
 
int
main(){
    
int
n,m;
    
while
(~
scanf
(
"%d%d"
,&n,&m)){
        
for
(
int
i=1;i<=n;i++){
            
scanf
(
"%d"
,&data[i]);
        
}
        
char
order;
        
int
a,b;
        
for
(;m--;){
            
scanf
(
" %c%d%d"
,&order,&a,&b);
            
if
(order==
'U'
){
                
update(a,b);
            
}
else
if
(order==
'Q'
){
                
if
(a>b)swap(a,b);
                
printf
(
"%d\n"
,querymax(a,b));
            
}
        
}
    
}
    
return
0;
}
……如果他们手一抖,写成N<=100000,M<=100000怎么办? 
!!!注意:以下内容涉及高级数据结构!!!
首先,有ACM经验的选手,一看这个题,第一反应,线段树好~
线段树这种数据结构,修改O(logn),查询O(logn),但是要预处理O(nlogn)
这个,如果没有ACM经验,也不打算认真做ACM的同学,看看就好。
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include <stdio.h>
#include <algorithm>
using
namespace
std;
 
const
int
MAXN=100000;
 
int
data[MAXN+5];
int
maxarr[MAXN*4+5];
 
void
build(
int
p,
int
l,
int
r) {
    
if
(l==r){
        
maxarr[p]=data[l];
        
return
;
    
}
    
int
m = ( l + r ) >> 1 ;
    
int
lchild=p<<1,rchild=p<<1|1;
    
build ( lchild , l , m ) ;
    
build ( rchild , m+1 , r ) ;
    
maxarr[p]=max(maxarr[lchild],maxarr[rchild]);
}
 
int
querymax (
int
L ,
int
R ,
int
p ,
int
l ,
int
r ) {
    
if
( L <= l && r <= R ) {
        
return
maxarr[p];
    
}
    
int
m = ( l + r ) >> 1 ;
    
int
lans=-1,rans=-1;
    
if
( L <= m ) lans=querymax ( L , R , p << 1 , l , m ) ;
    
if
( m <  R ) rans=querymax ( L , R , p << 1 | 1 , m + 1 , r ) ;
    
if
(lans==-1)
return
rans;
    
if
(rans==-1)
return
lans;
    
return
max(lans,rans);
}
 
void
update(
int
idx,
int
value,
int
p,
int
l,
int
r){
    
if
(l==r&&l==idx){
        
maxarr[p]=value;
        
return
;
    
}
    
int
m = ( l + r ) >> 1 ;
    
if
( idx <= m ) update( idx, value, p << 1, l, m );
    
if
( m <  idx ) update( idx, value, p << 1|1, m+1, r );
    
maxarr[p]=max(maxarr[p<<1],maxarr[p<<1|1]);
}
 
int
main(){
    
int
n,m;
    
while
(~
scanf
(
"%d%d"
,&n,&m)){
        
for
(
int
i=1;i<=n;i++){
            
scanf
(
"%d"
,&data[i]);
        
}
        
build(1,1,n);
        
char
order;
        
int
a,b;
        
for
(;m--;){
            
scanf
(
" %c%d%d"
,&order,&a,&b);
            
if
(order==
'U'
){
                
update(a,b,1,1,n);
            
}
else
if
(order==
'Q'
){
                
if
(a>b)swap(a,b);
                
printf
(
"%d\n"
,querymax(a,b,1,1,n));
            
}
        
}
    
}
    
return
0;
}
 有没有什么办法,普通人能去想出来,又不需要专门去学过高级数据结构呢?
有一个,叫块状链表(其实块状数组也行吧)。
好吧,其实分块的思想也不怎么常见,谈针对面试的算法的思路,都谈分治、贪心、递推、动态规划,没见人说过分块的样子。但是,分块是比较容易理解的。
很简单,现在我们把整个N大小的数组按顺序拆成sqrt(n)(根号n)个小数组,每个小数组有sqrt(n)个元素
比如 1 2 3 4 5 6 7 8 9
现在拆成
1 2 3
4 5 6
7 8 9
然后对每一个小块,我们除了改掉相应位置的值,还要额外记录一下整个小块的最大值。
如果我更新的时候,那个小块的最大值增大,那很简单,最大值也增大了。
如果把最大值改小了呢?为了正确性,只能把整个小块扫一遍,重新算出最大值了。
所以,修改的复杂度是O(sqrt(n))
现在看查询。我们要充分利用分小块以后的信息。
比如要查询2到9的最大值。按之前最朴素的暴力的做法,我要访问2、3、4、5、6、7、8、9
现在有小块的最大值信息了,我只要判断每个小块是否在查询区间内,不在的没用,一部分在的,就暴力查找,如果是完整在查询区间内的,我们就利用之前算好的这个小块内的最大值。
所以,分块的情况下,查询2到9的最大值,需要看看2、3,以及4~6的最大值,7~9的最大值。
很容易证明,查询的复杂度是O(sqrt(n))的(最坏是sqrt(n)个块全部要用,左右2边只盖住sqrt(n)-1个数,要暴力遍历过去)
//TODO:在这里补上分块法的代码
3种流派全部可过,但是明显的,在极限数据情况下,能够轻易区分出普通应聘者,会动脑的应聘者和有ACM经验的应聘者了。

 

转载于:https://www.cnblogs.com/Renyi-Fan/p/7779097.html

你可能感兴趣的文章
关于vs2010开发的ASP项目部署到XPSP2系统上出现找不到Reportviewer.XX.文件的解决方案...
查看>>
CSS中style用法详解
查看>>
Exception in thread "main" org.hibernate.MappingException: Unknown entity: com.mao.PersonSet
查看>>
序列终结者
查看>>
以python为例讲解闭包机制
查看>>
MongoDB:mongodb的索引操作
查看>>
【酷熊科技】工作积累 ----------- Unity3D
查看>>
Python格式化字符串、占位符、合并数组
查看>>
Python--day72--ajax完整版
查看>>
require循环依赖
查看>>
svg_path
查看>>
Java中数据表的建立
查看>>
iOS 线程安全--锁
查看>>
U3D协程Coroutine之WWW与Update()的并行测试
查看>>
LUA upvalue使用陷阱一例
查看>>
Java类加载机制(仅作记录)
查看>>
C#网络编程(接收文件) - Part.5
查看>>
json-server 详解
查看>>
向重复劳动说不!——GMExplorer 1.0 Beta 发布
查看>>
STL简单应用
查看>>