题目-楼兰图腾

问题分析
统计三元组, 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 1∼k−1中有多少个 y y y值是大于 y k y_k yk的
- 从左向右计算 g g g数组
- 再从右向左统计 k + 1 ∼ n k + 1 \sim n k+1∼n中有多少个 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;
}

京公网安备 11010502036488号