Hdu 3410 【单调队列】.cpp
题意:
给出一个数组,问你对于第i个数,从最后一个比它大的数到它之间比它小的数中最大的那个数的下标,以及它右边到第一个比它大的数中比它小的数中最大的那一个数的下标<下标从1开始>。
eg:5 2 4 3 1
l 0 0 2 0 0 对5来说左边比它小的数没有,所以是0。对2来说左边比它小的数没有,所以是0。对4来说左边比它小的数是2,所以下标是2。
r 3 0 4 5 0 对5来说右边比它小的数中最大的是4,是第3个,所以答案是3。对2来说右边比它小的数是1,但是4比2大,所以无法到达1,所以答案是0。对于4,右边比它小的数中最大一个3的下标是4,所以答案是4。
思路:
单调队列。
先从左向右维护一个单调队列,然后在维护过程中最后一个从队列中剔除掉的即右边比它小的数中最大的那一个。
单调队列中的值是下标值。
从右向左再维护一个单调队列就可以求出另一个值。
Tips:
nothing..
Code:
1 #include <stdio.h> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 const int MAXN = 50010; 7 8 int main() 9 { 10 freopen("in.txt", "r", stdin); 11 int iCase, n, ic = 1; 12 int arr[MAXN], que[MAXN]; 13 int rear, front; 14 int l[MAXN], r[MAXN]; 15 bool flag; 16 scanf("%d", &iCase); 17 while (iCase--) { 18 arr[0] = 0; 19 memset(que, 0, sizeof(que)); 20 21 scanf("%d", &n); 22 for (int i = 1; i <= n; ++i) 23 scanf("%d", &arr[i]); 24 25 front = 0, rear = -1; 26 for (int i = 1; i <= n; ++i) { 27 flag = false; 28 while (front <= rear && arr[que[rear]] < arr[i]) { 29 flag = true; 30 rear--; 31 } 32 if (flag) l[i] = que[rear+1]; 33 else l[i] = 0; 34 que[++rear] = i; 35 } 36 37 front = 0, rear = -1; 38 for (int i = n; i >= 1; --i) { 39 flag = false; 40 while (front <= rear && arr[que[rear]] < arr[i]) { 41 flag = true; 42 rear--; 43 } 44 if (flag) r[i] = que[rear+1]; 45 else r[i] = 0; 46 que[++rear] = i; 47 } 48 49 printf("Case %d:\n", ic++); 50 for (int i = 1; i <= n; ++i) { 51 printf("%d %d\n", l[i], r[i]); 52 } 53 } 54 return 0; 55 }