初识ST算法
登山
问题描述:
有一座延绵不断、跌宕起伏的山,最低处海拔为0米,最高处海拔不超过8848米。从这座山的一端走到另一端的过程中,每走 1 米海拔高度就升高 1 米或者降低 1 米。有 Q 个登山队计划在这座山的不同区段登山,当他们攀到各自区段内的最高峰时,就会插上他们的队旗。请你写一个程序找出他们插旗的高度。
输入说明:
从CLIMB.IN 输入数据。第一行为 N(N≤106 ),表示山两端的跨度。接下来 N+1 行,每行一个非负整数Hi (i=0..N),表示该位置的海拔高度(单位:米),其中 H0=Hn=0。然后是一个正整数Q(Q≤7000),表示登山队的数量。紧跟的Q行,每行两个数Ai和Bi,表示第 i 个登山队攀爬的区段[Ai,Bi],其中0≤Ai≤Bi≤N。
输出说明:
答案输出到CLIMB.OUT,共Q行,每行一个整数,表示第 i 个登山队攀爬区段中最高点的高度。
样例输入:
10
0
1
2
3
2
3
4
3
2
1
0
5
0 10
2 4
3 7
7 9
8 8
样例输出:
4
3
4
3
2
分析:
就是一个比较显然的RMQ问题,
正好刚学的ST算法,来试验一番。
这道题不是完全考算法,
个人认为,有两点注意事项:
1.这个坐标是从0出发的,不要因为做题的惯性不考虑0
2.这个题的数据范围也是较大的,100万,
要是数组开的比较随意就完了。。。
应当用计算器算一下,
开100W*20的数组刚好够用,
(开始随意的就10W*200(惯性),结果最后俩点201了,
然后100W*200,爆内存。。。。)
内存用了82M。。。。。
program climb; var i,j,n,m,k,l,q,a,b:longint; d:array[0..1000000,0..20]of longint; function max(x,y:longint):Longint; begin if x>y then exit(x); exit(y); end; begin assign(input,'climb.in'); reset(input); assign(output,'climb.out'); rewrite(output); readln(n); for i:=0 to n do readln(d[i,0]); for j:=1 to trunc(ln(n)/ln(2)) do for i:=0 to n-1<<j+1 do d[i,j]:=max(d[i,j-1],d[i+1<<(j-1),j-1]); readln(q); for i:=1 to q do begin readln(a,b); k:=trunc(ln(b-a+1)/ln(2)); m:=max(d[a,k],d[b-1<<k+1,k]); writeln(m); end; close(input); close(output); end.