区区区间间间 思维+单调栈

区区区间间间

思维


观察到这就离胜利不远了

知道a[i] 的 左扩展 l[i] 和 右扩展 r[i] 时,
则以a[i] 作为最大值的区间个数可以计算出来

两边的数组合,加 一个端点是i ,另一个端点在 l[i] ~ r[i]中。
注意l[i] 取 >= 时,r[i] 应取 < 才能保证不重不漏。

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

#define endl '\n'
#define int long long
#define fi first
#define se second
#define pb push_back

#define foa(x, y, z) for(int x = (y), ooo = (z); x <= z; ++x)
#define fos(x, y, z) for(int x = (y), ooo = (z); x >= z; --x)
#define ckmax(x, y) ((x) < (y) ? (x) = (y), 1 : 0)
#define ckmin(x, y) ((x) > (y) ? (x) = (y), 1 : 0)

typedef pair<int, int> pii;
typedef long long ll;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 10;
int n, m;
int a[N], l[N], r[N];
int calc()
{
    vector<int> v;
    a[0] = inf;
    v.pb(0);
    foa(i, 1, n) {
//         l[i] = i;
        while(v.size() && a[v.back()] <= a[i]) {
//             l[i] = v.back();
            v.pop_back();
        }
        l[i] = v.back() + 1;
        v.pb(i);
    }
    v.clear();
    a[n + 1] = inf;
    v.pb(n + 1);
    fos(i, n, 1) {
//         r[i] = i;
        while(v.size() && a[v.back()] < a[i]) {
//             r[i] = v.back();
            v.pop_back();
        }
        r[i] = v.back() - 1;
        v.pb(i);
    }
    int res = 0;
    foa(i, 1, n) res += a[i] * (r[i] - l[i] + (i - l[i]) * (r[i] - i));
//     foa(i, 1, n) printf("--- %d %d %d\n", i, l[i], r[i]);
    return res;
}
void solve()
{
	cin >> n;
    foa(i, 1, n) cin >> a[i];
    int res = calc();
    foa(i, 1, n) a[i] = -a[i];
    res += calc();
    cout << res << endl;
}
signed main()
{
	// ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    int t;
    cin >> t;
    while(t--)
	solve();
    return 0;
}
posted @   1564269628  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
点击右上角即可分享
微信分享提示