码迷,mamicode.com
首页 > 其他好文 > 详细

[CF5E] Bindian Signalizing - 单调栈

时间:2021-02-18 13:17:15      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:lan   include   esc   out   直接   记录   last   c++   ==   

[CF5E] Bindian Signalizing - 单调栈

Description

给定一个环,环上 n 座山,若连接两座山的两个弧中有任何一个上没有比两座山更高的山,那么这两座山可以互相看见彼此。现在给定 n 座山的高度,求能够看见彼此信号的山的数量。

Solution

对于 x,y,如果 x!=y 我们用小的去统计大的,如果 x=y 我们把能相互看见的放在一起统计

设最高的山为 a0,也是 an,其余按顺序旋转排列

现在显然 0 和 n 可以看见所有的山

我们求出每个数前面第一个严格大于它的和右边第一个严格大于它的,位置分别记为 l,r,那么只要这两个存在,就会贡献一个 2

同时,考虑每个数和他右边第一个更大数之前的所有等大的数的贡献,假设有 c 个,那么这个数还贡献一个 c

但需要注意,如果 l,r 找不到,那么贡献直接记为 n-1

求 l,r 直接用单调栈即可,维护一个不严格单调递增的栈,每个元素被弹出时,记录一下它是被谁弹出的,这个家伙就是第一个严格比他大的

求 c,在弹栈的过程中用一个计数维护一下

#include <bits/stdc++.h>
using namespace std;

#define int long long

const int N = 1000005;

int n, a[N], b[N], s[N], top, l[N], r[N], c[N];

signed main()
{
    ios::sync_with_stdio(false);
    cin >> n;
    for (int i = 1; i <= n; i++)
        cin >> b[i];
    int maxpos = max_element(b + 1, b + n + 1) - b;
    for (int i = 0; i <= n; i++)
        a[i] = b[(maxpos + i - 1) % n + 1];
    top = 0;
    int last_pop = -1, last_pop_count = 0;
    for (int i = 0; i <= n; i++)
    {
        while (top && a[i] > a[s[top]])
        {
            if (last_pop == a[s[top]])
                ++last_pop_count;
            else
                last_pop_count = 0, last_pop = a[s[top]];
            c[s[top]] = last_pop_count;
            r[s[top]] = i, --top;
        }
        s[++top] = i;
        if (a[i] != last_pop)
            last_pop = -1, last_pop_count = 0;
    }
    while (top)
    {
        if (last_pop == a[s[top]])
            ++last_pop_count;
        else
            last_pop_count = 0, last_pop = a[s[top]];
        c[s[top]] = last_pop_count;
        r[s[top]] = -1, --top;
    }
    top = 0;
    for (int i = n; i >= 0; i--)
    {
        while (top && a[i] > a[s[top]])
        {

            l[s[top]] = i, --top;
        }
        s[++top] = i;
    }
    while (top)
        l[s[top]] = -1, --top;
    // for (int i = 0; i <= n; i++)
    //     cout << a[i] << " ";
    // cout << endl;
    // for (int i = 0; i <= n; i++)
    //     cout << l[i] << " ";
    // cout << endl;
    // for (int i = 0; i <= n; i++)
    //     cout << r[i] << " ";
    // cout << endl;
    // for (int i = 0; i <= n; i++)
    //     cout << c[i] << " ";
    // cout << endl;

    c[0] = 0;

    int ans = 0;
    for (int i = 0; i < n; i++)
    {
        if (a[i] < a[0])
        {
            ans += 2;
            if (l[i] == 0 && r[i] == n)
                ans--;
        }
        ans += c[i];
    }
    cout << ans << endl;
}

[CF5E] Bindian Signalizing - 单调栈

标签:lan   include   esc   out   直接   记录   last   c++   ==   

原文地址:https://www.cnblogs.com/mollnn/p/14406131.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!