初步学习了下单调队列,一个比较简单的数据结构,即队列中元素之间的关系具有单调性,而且,队首和队尾都可以进行出队操作,只有队尾可以进行入队操作。
详见 http://blog.csdn.net/code_pang/article/details/14104151
题意:给出n(n<=1000000)个数字的序列和整数k,其中k为一个窗口的长度,窗口开始在序列的最左,每次右移一次,问每次窗口内的最大最小值。
思路:
维护两个单调队列,分别用于查询最大最小值。
其中一个单调递增,插入元素x时找到第一个比x小的元素,在它右边插入x,删除x后面所有元素。
同时由于窗口的移动,每个元素都有时效性,插入x比x小但时效性已过的也一并删除。
查询操作则是从队首找出第一元素,在窗口内则为结果,若已失去时效性,则删去,然后继续往后找。
插入操作还可以用二分优化。

1 #include <cstdio>
2 #include <cstring>
3 #define N 1000005
4
5 struct Que
6 {
7 int i, x; //x为加入序号
8 }q1[N],q2[N];
9 int front1, front2, tail1, tail2;
10 int minx[N], maxx[N], n, k;
11
12 //递增找最小
13 void add1(int i, int x)
14 {
15 while(front1<=tail1)
16 {
17 if(i < q1[tail1].i+k && q1[tail1].x < x)
18 break;
19 tail1--;
20 }
21 q1[++tail1].x = x;
22 q1[tail1].i = i;
23 }
24
25 //递减找最大
26 void add2(int i, int x)
27 {
28 while(front2<=tail2)
29 {
30 if(i < q2[tail2].i+k && q2[tail2].x > x)
31 break;
32 tail2--;
33 }
34 q2[++tail2].x = x;
35 q2[tail2].i = i;
36 }
37
38 int query1(int i)
39 {
40 while(front1<=tail1 && i >= q1[front1].i+k)
41 front1++;
42 return q1[front1].x;
43 }
44
45 int query2(int i)
46 {
47 while(front2<=tail2 && i >= q2[front2].i+k)
48 front2++;
49 return q2[front2].x;
50 }
51
52 int main()
53 {
54 while(scanf("%d%d",&n,&k)!=EOF)
55 {
56 front1 = 0; tail1 = -1;
57 front2 = 0; tail2 = -1;
58 int x;
59 for(int i=1; i<=k-1; i++)
60 {
61 scanf("%d",&x);
62 add1(i, x);
63 add2(i, x);
64 }
65 for(int i=k; i<=n; i++)
66 {
67 scanf("%d",&x);
68 add1(i, x);
69 add2(i, x);
70 minx[i] = query1(i);
71 maxx[i] = query2(i);
72 }
73 for(int i=k; i<=n; i++)
74 {
75 if(i!=k) printf(" ");
76 printf("%d",minx[i]);
77 }
78 printf(" ");
79 for(int i=k; i<=n; i++)
80 {
81 if(i!=k) printf(" ");
82 printf("%d",maxx[i]);
83 }
84 printf(" ");
85
86 }
87 return 0;
88 }
2 #include <cstring>
3 #define N 1000005
4
5 struct Que
6 {
7 int i, x; //x为加入序号
8 }q1[N],q2[N];
9 int front1, front2, tail1, tail2;
10 int minx[N], maxx[N], n, k;
11
12 //递增找最小
13 void add1(int i, int x)
14 {
15 while(front1<=tail1)
16 {
17 if(i < q1[tail1].i+k && q1[tail1].x < x)
18 break;
19 tail1--;
20 }
21 q1[++tail1].x = x;
22 q1[tail1].i = i;
23 }
24
25 //递减找最大
26 void add2(int i, int x)
27 {
28 while(front2<=tail2)
29 {
30 if(i < q2[tail2].i+k && q2[tail2].x > x)
31 break;
32 tail2--;
33 }
34 q2[++tail2].x = x;
35 q2[tail2].i = i;
36 }
37
38 int query1(int i)
39 {
40 while(front1<=tail1 && i >= q1[front1].i+k)
41 front1++;
42 return q1[front1].x;
43 }
44
45 int query2(int i)
46 {
47 while(front2<=tail2 && i >= q2[front2].i+k)
48 front2++;
49 return q2[front2].x;
50 }
51
52 int main()
53 {
54 while(scanf("%d%d",&n,&k)!=EOF)
55 {
56 front1 = 0; tail1 = -1;
57 front2 = 0; tail2 = -1;
58 int x;
59 for(int i=1; i<=k-1; i++)
60 {
61 scanf("%d",&x);
62 add1(i, x);
63 add2(i, x);
64 }
65 for(int i=k; i<=n; i++)
66 {
67 scanf("%d",&x);
68 add1(i, x);
69 add2(i, x);
70 minx[i] = query1(i);
71 maxx[i] = query2(i);
72 }
73 for(int i=k; i<=n; i++)
74 {
75 if(i!=k) printf(" ");
76 printf("%d",minx[i]);
77 }
78 printf(" ");
79 for(int i=k; i<=n; i++)
80 {
81 if(i!=k) printf(" ");
82 printf("%d",maxx[i]);
83 }
84 printf(" ");
85
86 }
87 return 0;
88 }