其实,他就是问了这么一个问题,问所有区间的第二大的数之和,那么我们其实很容易发现一个规律,就是每个数会对答案产生的贡献。
每个数,在它的左边和右边,分别有第一个大于它的数,和第二个大于它的数,我们可以首先处理出来这个。然后看一下图例:
蓝色区间长度相乘加上红色区间长度相乘,所以不就是“本身”这个值产生的贡献的次数了吗?然后就可以计算出来了。
那么问题就转变成为怎么求左边的第一个比他大的,和第二个比他大的(右边同理),我们可以不断的向左二分区间最远到达长度,然后就可以求出来第一个大于它的值的所在的位子,然后再继续找下去,时间复杂度O(log * log),又因为要找N次,所以总的复杂度是O(N * logN * logN)。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-6
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, a[maxN], pre[maxN][2][2] = {0};
int t[2][maxN<<2];
inline void pushup(int *tree, int rt) { tree[rt] = max(tree[lsn], tree[rsn]); }
void update(int *tree, int rt, int l, int r, int qx, int val)
{
if(l == r) { tree[rt] = val; return; }
int mid = HalF;
if(qx <= mid) update(tree, Lson, qx, val);
else update(tree, Rson, qx, val);
pushup(tree, rt);
}
inline int query(int *tree, int rt, int l, int r, int ql, int qr)
{
if(ql <= l && qr >= r) return tree[rt];
int mid = HalF;
if(qr <= mid) return query(tree, QL);
else if(ql > mid) return query(tree, QR);
else return max(query(tree, QL), query(tree, QR));
}
ll ans = 0;
inline void solve(int id)
{
int l = 1, r = id - 1, mid = 0, ith = 0;
while(l <= r)
{
mid = (l + r)>>1;
if(query(t[0], 1, 1, N, mid, id - 1) > a[id])
{
l = mid + 1;
ith = mid;
}
else r = mid - 1;
}
if(ith == 0) return;
pre[id][0][0] = ith;
l = 1; r = ith - 1; ith = 0;
int nex_id = r;
while(l <= r)
{
mid = (l + r)>>1;
if(query(t[0], 1, 1, N, mid, nex_id) > a[id])
{
l = mid + 1;
ith = mid;
}
else r = mid - 1;
}
if(ith == 0) return;
pre[id][0][1] = ith;
}
inline void finsh(int id)
{
int l = id + 1, r = N, mid = 0, ith = 0;
while(l <= r)
{
mid = (l + r)>>1;
if(query(t[1], 1, 1, N, id + 1, mid) > a[id])
{
r = mid - 1;
ith = mid;
}
else l = mid + 1;
}
if(ith == 0) return;
pre[id][1][0] = ith;
l = ith + 1; r = N; ith = 0;
int nex_id = l;
while(l <= r)
{
mid = (l + r)>>1;
if(query(t[1], 1, 1, N, nex_id, mid) > a[id])
{
r = mid - 1;
ith = mid;
}
else l = mid + 1;
}
if(ith == 0) return;
pre[id][1][1] = ith;
}
int main()
{
scanf("%d", &N);
for(int i=1; i<=N; i++) scanf("%d", &a[i]);
for(int i=1; i<=N; i++) pre[i][1][1] = pre[i][1][0] = N + 1;
update(t[0], 1, 1, N, 1, a[1]);
for(int i=2; i<=N; i++)
{
solve(i);
update(t[0], 1, 1, N, i, a[i]);
}
update(t[1], 1, 1, N, N, a[N]);
for(int i=N-1; i>=1; i--)
{
finsh(i);
update(t[1], 1, 1, N, i, a[i]);
}
for(int i=1; i<=N; i++)
{
ans += 1LL * (pre[i][0][0] - pre[i][0][1]) * (pre[i][1][0] - i) * a[i];
ans += 1LL * (i - pre[i][0][0]) * (pre[i][1][1] - pre[i][1][0]) * a[i];
}
printf("%lld\n", ans);
return 0;
}