单调栈的应用,结合二分查找

单调栈可以获得比第一个比当前数大/小的数的位置。

使用deque也可以用来二分查找。

如下例题:

https://codeforces.com/contest/1696/problem/D

可以存储当前数的单调增栈和单调减栈,然后根据栈中首元素的相对位置,进行选择和二分查找。

复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;

void YD(LL T)
{
    LL n;
    cin >> n;
    vector<LL> nums(n);
    for (int i = 0; i < n; i++) cin >> nums[i];
    vector<LL> to_node(n);
    deque<int> up;
    deque<int> down;
    up.push_back(n - 1);
    down.push_back(n - 1);
    for (int i = n - 2; i >= 0; i--)
    {
        int num = nums[i];
        while (up.size() && num > nums[up.front()]) up.pop_front();
        while (down.size() && num < nums[down.front()]) down.pop_front();
        if (up.size() == 0) to_node[i] = down.back();
        else if (down.size() == 0)to_node[i] = up.back();
        else
        {
            if (up.front() > down.front())
            {
                int l = 0, r = down.size() - 1;
                while (l < r)
                {
                    int mid = (l + r + 1) / 2;
                    if (down[mid] < up.front())
                        l = mid;
                    else r = mid - 1;
                }
                to_node[i] = down[l];
            }
            else
            {
                int l = 0, r = up.size() - 1;
                while (l < r)
                {
                    int mid = (l + r + 1) / 2;
                    if (up[mid] < down.front())
                        l = mid;
                    else r = mid - 1;
                }
                to_node[i] = up[l];
            }
        }
        up.push_front(i);
        down.push_front(i);
    }

    int cur = 0;
    int res = 0;
    while (cur != n - 1)
    {
        cur = to_node[cur];
        res++;
    }
    cout << res << endl;

}

int main()
{
    int T = 1;
    cin >> T;
    while (T--)
    {
        YD(T);
    }
    return 0;
}
View Code
复制代码
复制代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int nums[300010];
int prev_max[300010];
int next_max[300010];
int prev_min[300010];
int next_min[300010];
int Dis(int left, int right, bool to_left)
{
    if (left == right) return 0;
    if (left + 1 == right) return 1;
    if (to_left)
    {
        if (right == prev_min[right])
        {
            return Dis(left, prev_max[right], true)+1;
        }
        else
        {
            return Dis(left, prev_min[right], true)+1;
        }
    }
    else
    {
        if (left == next_min[left])
        {
            return Dis(next_max[left],right, false) + 1;
        }
        else
        {
            return Dis(next_min[left], right, false) + 1;
        }
    }
}
void YD()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        cin >> nums[i];
    }
    prev_max[1] = prev_min[1] = 1;
    int cur_max = 1;
    int cur_min = 1;
    for (int i = 2; i <= n; i++)
    {
        if (nums[i] > nums[cur_max]) cur_max = i;
        if (nums[i] < nums[cur_min]) cur_min = i;
        prev_max[i] = cur_max;
        prev_min[i] = cur_min;
    }
    next_max[n] = next_min[n] = n;
    cur_max = n;
    cur_min = n;
    for (int i = n-1; i >=1; i--)
    {
        if (nums[i] > nums[cur_max]) cur_max = i;
        if (nums[i] < nums[cur_min]) cur_min = i;
        next_max[i] = cur_max;
        next_min[i] = cur_min;
    }
    int max_index = prev_max[n];
    int res = Dis(1, max_index, true)+Dis(max_index,n,false);
    cout << res << endl;
}

int main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int T = 1;
    cin >> T;
    while (T--)
    {
        YD();
    }
    return 0;
}
View Code
复制代码

 

posted @   80k  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
点击右上角即可分享
微信分享提示