Weakness
求数列区间 ({a_n}) 中满足 (i < j < k, a_i > a_j > a_k) 的 ((i, j, k)) 对的数目。
设对 (a_i),左侧大于 (a_i) 的数的数目为 (L_i),右侧小于 (a_i) 的数的数目为 (R_i),易知答案为 (sum_i L_i R_i)。
构建数值大小线段树,(L_i) 即为 (i - ext{query}(1, A_i)),反向建树同理可得 (R_i)。
#include <cstdio>
#include <cstring>
#include <algorithm>
#define lson k<<1, l, mid
#define rson k<<1|1, mid+1, r
using namespace std;
int n, A[1000003], L[1000003], R[1000003], M;
int t[1000003<<2];
long long ans;
void modify(int k, int l, int r, int x) {
if (l==r&&l==x) {++t[k]; return; }
register int mid=l+r>>1;
if (x<=mid) modify(lson, x);
if (mid<x) modify(rson, x);
++t[k];
}
int query(int k, int l, int r, int x, int y) {
if (x<=l&&r<=y) return t[k];
register int mid=l+r>>1, res=0;
if (x<=mid) res+=query(lson, x, y);
if (mid<y) res+=query(rson, x, y);
return res;
}
int main() {
scanf("%d", &n);
for (int i=1; i<=n; ++i) scanf("%d", &A[i]), M=max(M, A[i]);
for (int i=1; i<=n; ++i) modify(1, 1, M, A[i]), L[i]=i-query(1, 1, M, 1, A[i]);
memset(t, 0, sizeof t);
for (int i=n; i; --i) {modify(1, 1, M, A[i]); if (A[i]-1) R[i]=query(1, 1, M, 1, A[i]-1); else R[i]=0; }
for (int i=1; i<=n; ++i) ans+=(long long)L[i]*R[i];
printf("%lld
", ans);
return 0;
}