T1009 Triple Inversions
题目大意
如果在一个序列A中存在i<j<k, 且A_i>A_j>A_k,则(A_i, A_j, A_k)是一个三元逆序对。现要求统计给定数组中的三元逆序对的数量。
题目限制条件
- 时间限制:300ms
- 内存限制:64MB
本题考察知识点
- 树状数组
解题思路
用树状数组求二元逆序对是一道很经典的题。我们回顾一下求二元逆序对的过程:从后向前扫描,用树状数组维护每个数字出现的次数,本质上维护的是以每个数字为开头的一元逆序对的个数。当然,一元逆序对也就是数字本身出现的次数。
现在要求三元逆序对,自然想到用两个树状数组分别维护以每个数字为开头的一元逆序对和二元逆序对出现的次数。
注意整数类型要用long long,用int的话会有两个case溢出。
AC代码
/*
Data Structure and Algorithm.
Created by CLion
Author: Depressant
Date: 2022.4.26
Time: 下午 10:03
*/
#include "bits/stdc++.h"
#define maxn 100005
typedef long long ll;
int N;
ll cnt = 0;
int arr[maxn];
struct FenwickTree {
int len{};
std::vector<ll> _v;
void setLen(int l) {
len = l;
_v.resize(l + 1);
}
static int lowbit(int x) { return x & (-x); }
void update(int pos, ll val) {
while (pos <= len) {
_v[pos] += val;
pos += lowbit(pos);
}
}
ll query(int pos) {
ll ret = 0;
while (pos > 0) {
ret += _v[pos];
pos -= lowbit(pos);
}
return ret;
}
};
FenwickTree ft1, ft2;
void init() {
}
void read() {
std::cin >> N;
for (int i = 0; i < N; ++i) {
scanf("%d", &arr[i]);
}
ft1.setLen(N);
ft2.setLen(N);
}
void solve() {
for (int i = N - 1; i >= 0; --i) {
ll tmp = ft1.query(arr[i] - 1);
ft1.update(arr[i], 1);
cnt += ft2.query(arr[i] - 1);
ft2.update(arr[i], tmp);
}
std::cout << cnt;
}
int main() {
// freopen("Depressant.txt", "r", stdin);
init();
read();
solve();
return 0;
}