AcWing-4721.排队(单调栈+二分)

n 个小朋友排成一排,从左到右依次编号为 1∼n。

第 i 个小朋友的身高为 hi。

虽然队伍已经排好,但是小朋友们对此并不完全满意。

对于一个小朋友来说,如果存在其他小朋友身高比他更矮,却站在他右侧的情况,该小朋友就会感到不满。

每个小朋友的不满程度都可以量化计算,具体来说,对于第 i 个小朋友:

  • 如果存在比他更矮且在他右侧的小朋友,那么他的不满值等于其中最靠右的那个小朋友与他之间的小朋友数量。
  • 如果不存在比他更矮且在他右侧的小朋友,那么他的不满值为 −1。

请你计算并输出每个小朋友的不满值。

注意,第 1 个小朋友和第 2 个小朋友之间的小朋友数量为 0,第 1 个小朋友和第 4 个小朋友之间的小朋友数量为 2。

输入格式

第一行包含整数 n。

第二行包含 n 个整数 h1,h2,…,hn。

输出格式

共一行,输出 n 个整数,第 i 个整数为第 i 个小朋友的不满值。

数据范围

前 5 个测试点满足 2≤n≤5。
所有测试点满足 2≤n≤1e5,1≤hi≤1e9。

输入样例1:

6
10 8 5 3 50 45

输出样例1:

2 1 0 -1 0 -1

输入样例2:

7
10 4 6 3 2 8 15

输出样例2:

4 2 1 0 -1 -1 -1 

输入样例3:

5
10 3 1 10 11

输出样例3:

1 0 -1 -1 -1 

该题单调栈+二分。(明明比赛时想到单调栈了,但却做不成ort....太菜了)

这题对于序列a1,a2,...,ai,aj,..,an,如果ai>=aj的话,那么ai将毫无用处,因为假设ai前面存在一个数ak,并且ak>ai,因为ai>=aj,所以ak>aj,因此小于ak的最右边的数是aj,不满值为j-k-1,ai没有任何用处。因此该题从后往前遍历,并且维护单调栈,遍历到每个数ai时对单调栈里的数进行二分,查找比ai小的数即可。找到就更新,找不到就-1 。

代码如下:

#include<iostream>
using namespace std;
const int N = 1e5+5;
typedef pair<int, int> PII;
int res[N], k = 0; //k是栈顶 
PII a[N], st[N]; //原数组,单调栈数组 
int bin(int l, int r, int tar) //二分查找 
{
    while(l<r)
    {
        int mid = l + r >> 1;
        if(st[mid].first<tar) r = mid;
        else l = mid + 1;
    }
    return l;
}
int main()
{
    int n;
    cin >> n;
    for(int i=0; i<n; i++) cin >> a[i].first, a[i].second = i; //第一参数存数值,第二个存下标 
    for(int i=n-1; i>=0; i --)
    {
        if(!k) res[i] = -1;
        else
        {
            int t = bin(1, k, a[i].first); //查找比a[i]小的数 
            if(st[t].first<a[i].first) res[i] = st[t].second - i - 1; //找到的情况 
            else res[i] = -1; //找不到的情况 
        }
        if(a[i].first<st[k].first || !k) st[++ k] = a[i]; //如果ai小于栈顶的元素,则入栈 
    }
    for(int i=0; i<n; i++) cout << res[i] << " ";
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值