题目链接:link
题目大意:
Erwin 最近对一种叫thair
的东西巨感兴趣。在含有 n 个整数的序列
a
1
,
a
2
,
…
,
a
n
a_1,a_2,\ldots,a_n
a1,a2,…,an 中,三个数被称作thair
当且仅当 i < j < k 且
a
i
<
a
j
<
a
k
a_i<a_j<a_k
ai<aj<ak,求一个序列中 thair
的个数。
解题思路:
对于三元组,首先应该想到枚举中间的元素 ,用L[ i ]记录a[ i ]左边小于a[ i ]的元素个数,用R[ i ]记录a[ i ]右边大于a[ i ]的元素个数。
根据乘法原理有: 以a[ i ]为中间元素的合法子序列个数为L[ i ] * R[ i ]。
对于L和R数组可以用树状数组或者线段树求解,在这里写一下线段树的做法。
拓展: 对于三元子序列问题,不管是上升子序列,下降子序列,V
型或者 ∧
型都可以用这种方法来做。
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 3e4 + 10;
ll a[N], L[N], R[N];
vector<ll> alls;
struct node
{
int l, r;
int sum;
}tr[N << 2];
void pushup(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void build(int l, int r, int u = 1)
{
tr[u] = { l,r,0 };
if (l == r) return;
int mid = l + r >> 1;
build(l, mid, u << 1); build(mid + 1, r, u << 1 | 1);
pushup(u);
}
void modify(int x, int u = 1)
{
if (tr[u].l == tr[u].r) tr[u].sum++;
else
{
int mid = tr[u].l + tr[u].r >> 1;
if (x <= mid) modify(x, u << 1);
else modify(x, u << 1 | 1);
pushup(u);
}
}
int query(int l, int r, int u = 1)
{
if (tr[u].l >= l && tr[u].r <= r) return tr[u].sum;
int mid = tr[u].l + tr[u].r >> 1;
int ans = 0;
if (l <= mid) ans = query(l, r, u << 1);
if (r > mid) ans += query(l, r, u << 1 | 1);
return ans;
}
int main()
{
int n; cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
alls.push_back(a[i]);
}
sort(alls.begin(), alls.end());
alls.erase(unique(alls.begin(), alls.end()), alls.end());
build(1, n);
for (int i = 1; i <= n; i++)
{
int k = lower_bound(alls.begin(), alls.end(), a[i]) - alls.begin() + 1;
L[i] = query(1, k - 1);
modify(k);
}
build(1, n);
for (int i = n; i >= 1; i--)
{
int k = lower_bound(alls.begin(), alls.end(), a[i]) - alls.begin() + 1;
R[i] = query(k + 1, n);
modify(k);
}
ll ans = 0;
for (int i = 1; i <= n; i++)ans += L[i] * R[i];
cout << ans << endl;
return 0;
}