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 }
View Code

 

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3410

转载于:https://www.cnblogs.com/Griselda/p/3217105.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值