题目-楼兰图腾

在这里插入图片描述

问题分析

统计三元组, i < j < k i < j < k i<j<k, 分别满足 f ( j ) > f ( i ) < f ( k ) f(j) > f(i) < f(k) f(j)>f(i)<f(k), f ( i ) < f ( j ) > f ( k ) f(i) < f(j) > f(k) f(i)<f(j)>f(k)
在这里插入图片描述

按照集合思想考虑, 将所有的 V V V, 按照最下面的点进行分类, 假设最下面的点分为 y 1 , y 2 , y 3 , . . . , y k y_1, y_2, y_3, ..., y_k y1,y2,y3,...,yk, 假设当前点的纵坐标是 y k y_k yk

需要统计左边 > y k > y_k >yk的数量 a a a和右边 > y k > y_k >yk的数量 b b b, 那么当前位置的方案数量 a × b a \times b a×b

现在问题变成了如何统计当前位置前面和后面大于 y k y_k yk的数量
可以使用权值树状数组解决

算法步骤

  • 定义数组 g ( k ) g(k) g(k), 表示 1 ∼ k − 1 1 \sim k - 1 1k1中有多少个 y y y值是大于 y k y_k yk
  • 从左向右计算 g g g数组
  • 再从右向左统计 k + 1 ∼ n k + 1 \sim n k+1n中有多少个 y y y的值是大于 y k y_k yk
  • 乘法原理累计方案数, 并且将当前位置 y k y_k yk加入到集合中
  • ^同理

代码实现

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;
const int N = 2e5 + 10;

int n, w[N];
LL tr[N];
LL g[N], l[N];

int lowbit(int x) {
   
    return x & -x;
}

void modify(int u, int val) {
   
    for (int i = u; i <= n; i += lowbit(i)) tr[i] += val;
}

LL get(int u) {
   
    LL ans = 0;
    for (int i = u; i; i -= lowbit(i)) ans += tr[i];
    return ans;
}

int main() {
   
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin >> n;
    for (int i = 0; i < n; ++i) cin >> w[i];

    for (int i = 0; i < n; ++i) {
   
        int val = w[i];
        g[i] = get(n) - get(val);
        l[i] = get(val - 1);
        modify(val, 1);
    }

    memset(tr, 0, sizeof tr);

    LL g_ans = 0, l_ans = 0;
    for (int i = n - 1; i >= 0; --i) {
   
        int val = w[i];
        g_ans += (LL) g[i] * (get(n) - get(val));
        l_ans += (LL) l[i] * get(val - 1);
        modify(val, 1);
    }

    cout << g_ans << ' ' << l_ans << '\n';
    return 0;
}