Codeforces1313 C. Skyscrapers(单调队列 or RMQ)

Description:

The outskirts of the capital are being actively built up in Berland. The company “Kernel Panic” manages the construction of a residential complex of skyscrapers in New Berlskva. All skyscrapers are built along the highway. It is known that the company has already bought n plots along the highway and is preparing to build n skyscrapers, one skyscraper per plot.

Architects must consider several requirements when planning a skyscraper. Firstly, since the land on each plot has different properties, each skyscraper has a limit on the largest number of floors it can have. Secondly, according to the design code of the city, it is unacceptable for a skyscraper to simultaneously have higher skyscrapers both to the left and to the right of it.

Formally, let’s number the plots from 1 1 1 to n n n. Then if the skyscraper on the i-th plot has a i a_i ai floors, it must hold that ai is at most m i ( 1 ≤ a i ≤ m i ) m_i (1≤a_i≤mi) mi(1aimi). Also there mustn’t be integers j j j and k k k such that j < i < k jj<i<k and a j > a i < a k a_j>a_iaj>ai<ak. Plots j j j and k k k are not required to be adjacent to i i i.

The company wants the total number of floors in the built skyscrapers to be as large as possible. Help it to choose the number of floors for each skyscraper in an optimal way, i . e i.e i.e. in such a way that all requirements are fulfilled, and among all such construction plans choose any plan with the maximum possible total number of floors.

Input

The first line contains a single integer n ( 1 ≤ n ≤ 500000 ) n (1≤n≤500000) n(1n500000) — the number of plots.

The second line contains the integers m 1 , m 2 , … , m n ( 1 ≤ m i ≤ 1 0 9 ) m_1,m_2,…,m_n (1≤m_i≤10^9) m1,m2,,mn(1mi109) — the limit on the number of floors for every possible number of floors for a skyscraper on each plot.

Output

Print n n n integers a i a_i ai — the number of floors in the plan for each skyscraper, such that all requirements are met, and the total number of floors in all skyscrapers is the maximum possible.

If there are multiple answers possible, print any of them.

Examples

input

5
1 2 3 2 1

output

1 2 3 2 1

input

3
10 6 8

output

10 6 6

Note

In the first example, you can build all skyscrapers with the highest possible height.

In the second test example, you cannot give the maximum height to all skyscrapers as this violates the design code restriction. The answer [ 10 , 6 , 6 ] [10,6,6] [10,6,6] is optimal. Note that the answer of [ 6 , 6 , 8 ] [6,6,8] [6,6,8] also satisfies all restrictions, but is not optimal.

题意:

给出一个长度为 n n n 的序列,把这个序列变成一个不存在对于任何一个元素两边都比他大的序列,就是类似一个倒 v v v,对于 C 1 C1 C1 数据很小,怎么做都行。
复杂度更低的做法就是用单调队列来维护峰值,然后维护 n n n 个数以后再遍历一遍找到和最大的那个,具体操作可以看代码。

AC代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define sd(n) scanf("%d", &n)
#define sdd(n, m) scanf("%d%d", &n, &m)
#define sddd(n, m, k) scanf("%d%d%d", &n, &m, &k)
#define pd(n) printf("%d\n", n)
#define pc(n) printf("%c", n)
#define pdd(n, m) printf("%d %d\n", n, m)
#define pld(n) printf("%lld\n", n)
#define pldd(n, m) printf("%lld %lld\n", n, m)
#define sld(n) scanf("%lld", &n)
#define sldd(n, m) scanf("%lld%lld", &n, &m)
#define slddd(n, m, k) scanf("%lld%lld%lld", &n, &m, &k)
#define sf(n) scanf("%lf", &n)
#define sc(n) scanf("%c", &n)
#define sff(n, m) scanf("%lf%lf", &n, &m)
#define sfff(n, m, k) scanf("%lf%lf%lf", &n, &m, &k)
#define ss(str) scanf("%s", str)
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, n, a) for (int i = n; i >= a; i--)
#define mem(a, n) memset(a, n, sizeof(a))
#define debug(x) cout << #x << ": " << x << endl
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define fi first
#define se second
#define mod(x) ((x) % MOD)
#define gcd(a, b) __gcd(a, b)
#define lowbit(x) (x & -x)
typedef pair<int, int> PII;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
inline int read()
{
    int ret = 0, sgn = 1;
    char ch = getchar();
    while (ch < '0' || ch > '9')
    {
        if (ch == '-')
            sgn = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9')
    {
        ret = ret * 10 + ch - '0';
        ch = getchar();
    }
    return ret * sgn;
}
inline void Out(int a) //Êä³öÍâ¹Ò
{
    if (a > 9)
        Out(a / 10);
    putchar(a % 10 + '0');
}

ll gcd(ll a, ll b)
{
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b)
{
    return a * b / gcd(a, b);
}
///快速幂m^k%mod
ll qpow(ll x, ll n, ll mod)
{
    if (n == 0)
        return 1;
    ll res = qpow((x * x) % mod, n / 2, mod) % mod;
    if (n & 1)
        res = (res * x) % mod;
    return res % mod;
}
// 快速幂求逆元
int Fermat(int a, int p) //费马求a关于b的逆元
{
    return qpow(a, p - 2, p);
}

///扩展欧几里得
ll exgcd(ll a, ll b, ll &x, ll &y)
{
    if (b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    ll g = exgcd(b, a % b, x, y);
    ll t = x;
    x = y;
    y = t - a / b * y;
    return g;
}

const int N = 500010;
ll a[N], b[N], x[N], y[N], ans, sum;
int tmp, n, pos = 0, res[N];

int main()
{
    sd(n);
    pos = 0;
    rep(i, 1, n)
    {
        sld(a[i]);
        b[i] = a[i];
    }
    sum = pos = 0;
    rep(i, 1, n)
    {
        while (pos && b[i] <= b[res[pos]])
        {
            sum -= 1ll * (res[pos] - res[pos - 1]) * b[res[pos]];
            pos--;
        }
        res[++pos] = i;
        sum += 1ll * (res[pos] - res[pos - 1]) * b[i];
        x[i] = sum;
    }
    for (int i = 1; i * 2 <= n; ++i)
    {
        swap(b[i], b[n - i + 1]);
    }
    sum = pos = 0;
    rep(i, 1, n)
    {
        while (pos && b[i] <= b[res[pos]])
        {
            sum -= 1ll * (res[pos] - res[pos - 1]) * b[res[pos]];
            pos--;
        }
        res[++pos] = i;
        sum += 1ll * (res[pos] - res[pos - 1]) * b[i];
        y[i] = sum;
    }
    rep(i, 1, n)
    {
        if (ans < x[i] + y[n - i + 1] - a[i])
        {
            ans = x[i] + y[n - i + 1] - a[i];
            tmp = i;
        }
    }
    per(i, tmp - 1, 1)
    {
        a[i] = min(a[i], a[i + 1]);
    }
    rep(i, tmp + 1, n)
    {
        a[i] = min(a[i], a[i - 1]);
    }
    rep(i, 1, n)
        printf("%lld ", a[i]);
    printf("\n");
    return 0;
}

下面学习了一种更好理解的RMQ做法,整体思路是一样的,就是维护起来比较简单。

先RMQ处理数据,对于每一个位置,二分找里当前位置最近的那个小于当前位置值的位置,比如53454,对最后一个4,就是找到3,就是把53454,变成53444,第一个比自己小到自己中间一段变得和自己一样。

prei是以i为最高点让1-i递增的最小耗费,suf是以i为最高点让i-n递减的最小耗费。
然后遍历一遍求出以每个位置作为峰值的最小花费即可。

AC代码:

const int N = 500010;
int n, x, y;
ll a[N];
ll dp[N][25];
ll pre[N], suf[N];
void rmq_init()
{
    for (int i = 1; i <= n; i++)
        dp[i][0] = a[i];
    for (int j = 1; (1 << j) <= n; j++)
        for (int i = 1; i + (1 << j) - 1 <= n; i++)
            dp[i][j] = min(dp[i][j - 1], dp[i + (1 << j - 1)][j - 1]);
}
ll rmq_query(int l, int r)
{
    int k = log2(r - l + 1);
    return min(dp[l][k], dp[r - (1 << k) + 1][k]);
}

void solve(ll t[])
{
    t[1] = a[1];
    rep(i, 2, n)
    {
        if (rmq_query(1, i - 1) >= a[i])
            t[i] = i * a[i]; //前面的都比当前位置的高,就变成当前位置这个高度。
        else
        {
            int l = 1, r = i - 1, ans, mid;
            while (l <= r)
            {
                mid = (l + r) >> 1;
                if (rmq_query(mid, r) < a[i]) //右半区间存在比当前位置低的
                    l = mid + 1, ans = mid;
                else
                    r = mid - 1;
            }
            t[i] = (i - ans) * a[i] + t[ans];
        }
    }
}
int main()
{
    sd(n);
    rep(i, 1, n)
        sld(a[i]);
    rmq_init();
    solve(pre);
    reverse(a + 1, a + 1 + n);
    rmq_init();
    solve(suf);
    int id;
    ll ans = 0;
    reverse(a + 1, a + 1 + n);
    rmq_init();
    rep(i, 1, n)
    {
        if (pre[i] + suf[n - i + 1] - a[i] > ans)
        {
            ans = pre[i] + suf[n - i + 1] - a[i];
            id = i;
        }
    }
    rep(i, 1, id)
    {
        printf("%lld ", rmq_query(i, id));
    }
    vector<ll> rec;
    per(i, n, id + 1)
        rec.pb(rmq_query(id, i));
    int len = rec.size();
    per(i, len - 1, 0)
        printf("%lld ", rec[i]);
    puts("");
    return 0;
}

你可能感兴趣的:(数据结构————单调队列,CodeForces)