这是一道题意简单,数据较大的题(喜闻乐见);

一开始可能会想到RMQ问题,ST,线段树都是O(nlogn),应该勉强能过(没试过);

由于这道题区间是滚动连续的,所以,可以使用单调队列!

以最小值为例:

对于a[i],a[j],i>j;

如果a[i]<a[j],那么在加入i到滚动窗口中,找最小值一定不用考虑a[j];

因为a[j]比a[i]要先退出窗口,且即便i,j都在窗口中,那么a[j]一定不是最小值(a[i]<a[j]);

所以我们维护一个单调升序队列,对于新加入的元素,如果比队尾元素大,那么在队尾处入队(可能成为某个区间最小值);

否则的话,找打一个合适的位置m使之前位置的树比它小,后面的数比它大,同时将位置m后面的数全部退队;

由于单调队列是随着下标递增的,那么对于滚动窗口滚出的元素,从队头判断即可。

 1 var ans:array[0..1000000,1..2] of longint;
 2     a,w:array[0..1000000] of longint;
 3     h,f,r,mid,m,n,i,v:longint;
 4 begin
 5   readln(n,m);
 6   for i:=1 to n do
 7     read(a[i]);
 8   a[0]:=-2147483647;
 9   for i:=1 to n do
10   begin
11     if a[i]>a[w[h]] then
12     begin
13       h:=h+1;
14       w[h]:=i;
15     end
16     else begin
17       f:=1;
18       r:=h;
19       repeat
20         mid:=(f+r) div 2;
21         if (a[w[mid]]>=a[i]) and (a[w[mid-1]]<a[i]) then break;
22         if (a[w[mid]]>=a[i]) then r:=mid-1 else f:=mid+1;
23       until f>r;
24       h:=mid;
25       w[h]:=i;
26     end;
27     if i>=m then
28     begin
29       f:=1;
30       r:=h;
31       v:=0;
32       repeat
33         mid:=(f+r) div 2;
34         if w[mid]<i-m+1 then f:=mid+1;
35         if w[mid]>=i-m+1 then
36         begin
37           v:=mid;
38           r:=mid-1;
39         end;
40       until f>r;
41       ans[i-m+1,1]:=a[w[v]];
42     end;
43   end;
44   a[0]:=2147483647;
45   h:=0;
46   fillchar(w,sizeof(w),0);
47   for i:=1 to n do
48   begin
49     if a[i]<a[w[h]] then
50     begin
51       h:=h+1;
52       w[h]:=i;
53     end
54     else begin
55       f:=1;
56       r:=h;
57       repeat
58         mid:=(f+r) div 2;
59         if (a[w[mid]]<=a[i]) and (a[w[mid-1]]>a[i]) then break;
60         if (a[w[mid]]<=a[i]) then r:=mid-1 else f:=mid+1;
61       until f>r;
62       h:=mid;
63       w[h]:=i;
64     end;
65     if i>=m then
66     begin
67       f:=1;
68       r:=h;
69       v:=0;
70       repeat
71         mid:=(f+r) div 2;
72         if w[mid]<i-m+1 then f:=mid+1;
73         if w[mid]>=i-m+1 then
74         begin
75           v:=mid;
76           r:=mid-1;
77         end;
78       until f>r;
79       ans[i-m+1,2]:=a[w[v]];
80     end;
81   end;
82   for i:=1 to n-m+1 do
83     write(ans[i,1],' ');
84   writeln;
85   for i:=1 to n-m+1 do
86     write(ans[i,2],' ');
87   writeln;
88 end.
View Code

单调队列,关键在于看出题目中的单调性;

还有单调队列一般存放标号比较方便

 

posted on 2013-12-05 20:34  acphile  阅读(134)  评论(0)    收藏  举报