1. 程式人生 > 實用技巧 >三元上升子序列

三元上升子序列

題目

求滿足 \(i < j < k,a_i < a_j < a_k\) 的三元組的個數

思路

考慮三元組中間的數
那麼它對答案的貢獻是它前面比他小的數的個數乘上它後面比他大的數的個數
樹狀陣列維護就好了

\(Code\)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit (x & (-x))
#define LL long long
using namespace std;

const int N = 3e4 + 5;
int n , m , a[N] , ind[N] , c[N] , l[N] , r[N];
LL ans;

inline void add(int x){for(; x <= m; x += lowbit) c[x] += 1;}
inline int query(int x)
{
	int res = 0;
	for(; x; x -= lowbit) res += c[x];
	return res;
}

int main()
{
	scanf("%d" , &n);
	for(register int i = 1; i <= n; i++) scanf("%d" , &a[i]) , ind[i] = a[i];
	sort(ind + 1 , ind + n + 1);
	m = unique(ind + 1 , ind + n + 1) - ind - 1;
	for(register int i = 1; i <= n; i++)
	{
		int k = lower_bound(ind + 1 , ind + m + 1 , a[i]) - ind;
		l[i] = query(k - 1) , add(k);
	}
	memset(c , 0 , sizeof c);
	for(register int i = n; i; i--)
	{
		int k = lower_bound(ind + 1 , ind + m + 1 , a[i]) - ind;
		r[i] = query(m) - query(k) , add(k);
	}
	for(register int i = 1; i <= n; i++) ans += 1LL * l[i] * r[i];
	printf("%lld" , ans);
}