题目: | 忠诚 | |
来源: | Tyvj 1038 | |
题目大意: | 给出N个数,M次询问,每次输出(a,b)中的最小值 | |
数据范围: | m<=100000,n<=100000 | |
样例: | 10 3 1 2 3 4 5 6 7 8 9 10 2 7 3 9 1 10 | 2 3 1 |
做题思路: | 曾经痴迷的线段树,现在才感到st的伟大,没有了线段树的繁琐,却依存那光速的时 间。纯RMQ不解释 | |
知识点: | RMQ,st算法,线段树 |
//线段树做法
const MaxN=100010;
type
tre=record
l,r,lc,rc,min:longint;{<左右边界、左右儿子、区间最小值>}
end;//tre
var
tree:array[0..MaxN*4] of tre;
n,m,i,j,x,a,b,root,tot,ans:longint;
procedure build(vart:longint;l,r:longint);{<建树>}
begin
inc(tot);t:=tot;
tree[t].l:=l;tree[t].r:=r;
tree[t].min:=maxlongint;
ifl<>r then
begin
build(tree[t].lc,l,(l+r)div 2);
build(tree[t].rc,(l+r)div 2+1,r);
end;//if
end;
procedure insert(t,i:longint);{<伪插入,其实是不断更新i到叶子前所经过的枝干的最小值>}
begin
ift=0 then exit;
ifx<tree[t].min then tree[t].min:=x;{<更新>}
iftree[tree[t].lc].r>=i then insert(tree[t].lc,i)
else insert(tree[t].rc,i);
end;
procedure find(t,l,r:longint);{<查找对应区间>}
begin
ift=0 then exit;
if(tree[t].l=l)and(tree[t].r=r) then
begin
ifans>tree[t].min then ans:=tree[t].min;{<由于该区间可能跨越子树,所以做下比较>}
exit;
end;
iftree[tree[t].lc].r>=r then find(tree[t].lc,l,r)
else
iftree[tree[t].rc].l<=l then find(tree[t].rc,l,r)
else
begin
find(tree[t].lc,l,tree[tree[t].lc].r);
find(tree[t].rc,tree[tree[t].rc].l,r);
end;
end;
begin
readln(m,n);
root:=0;tot:=0;
build(root,1,m);
fori:=1 to m do
begin
read(x);
insert(root,i);
end;
fori:=1 to n do
begin
readln(a,b);
ans:=maxlongint;{<初始化maxlongint才能不断更新>}
find(root,a,b);
write(ans,' ');
end;
end.
//ST做法
var
f:array[0..100010,0..20]of longint;
n,m,i,j,x,y,k:longint;
function min(a,b:longint):longint;
begin
ifa>b then exit(b);
exit(a);
end;
begin
readln(n,m);
fori:=1 to n do
read(f[i,0]);
readln;
forj:=1 to trunc(ln(n)/ln(2)) do
fori:=1 to n+1-1 shl j do
begin
f[i,j]:=min(f[i,j-1],f[i+1 shl (j-1),j-1]);
end;
fori:=1 to m do
begin
readln(x,y);
k:=trunc(ln(y-x+1)/ln(2));
write(min(f[x,k],f[y+1-1 shl k,k]));
ifi<>m then write(' ') else writeln;
end;
end.
题目来源:
http://www.tyvj.cn:8080/Problem_Show.asp?id=1038