题目描述
Erwin最近对一种叫"thair"的东西巨感兴趣。。。
在含有n个整数的序列a1,a2......an中,
三个数被称作"thair"当且仅当i<j<k且ai<aj<ak
求一个序列中"thair"的个数。
输入输出格式
输入格式:开始一个正整数n,
以后n个数a1~an。
输出格式:"thair"的个数
输入输出样例
输入样例#1:
4 50 18 3 4 6 8 14 15 16 17 21 25 26 Input 4 2 1 3 4 Output 2 Input 5 1 2 2 3 4 Output 7 对样例2的说明: 7个"thair"分别是 1 2 3 1 2 4 1 2 3 1 2 4 1 3 4 2 3 4 2 3 4
输出样例#1:
说明
约定30%的数据n<=100
60%的数据n<=2000
100%的数据n<=30000
大数据随机生成
0<=a[i]<=maxlongint
离散化 + 树状数组
1.显然,对于所有的三元上升子序列,我们只需要考察中间的元素,即对于每个元素,我们要求出其左边严格小于它的数的个数d和右边严格大于它的数的个数u,然后将u*d统计进答案即可
2.考虑如何求u和d,显然我们需要借助一颗权值线段树,然而这里可以用树状数组,我们只需要维护两颗树状数组,一个正向添加数字,一个反向添加数字,然后边添加边统计有多少个严格大于/小于它的数字即可(当然需要离散化)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN=30005;
int a[MAXN],b[MAXN],c[MAXN],d[MAXN],tree[MAXN],l[MAXN],r[MAXN],n;
bool cmp(int x,int y)
{
return a[x]<a[y];
}
int Lowbit(int x)
{
return x&(-x);
}
void Add(int x)
{
while(x<=n){
tree[x]++;
x+=Lowbit(x);
}
}
int Sum(int x)
{
int res=0;
while(x>0){
res+=tree[x];
x-=Lowbit(x);
}
return res;
}
int main()
{
int i,j=0;
long long ans=0;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=i;
}
sort(b+1,b+1+n,cmp);
for(i=1;i<=n;i++){
if(a[b[i]]!=a[b[i-1]]){
c[b[i]]=++j;
}
else{
c[b[i]]=j;
}
}
for(i=1;i<=n;i++){
Add(c[i]);
l[i]=Sum(c[i]-1);
}
memset(tree,0,sizeof(tree));
for(i=1;i<=n;i++){
d[i]=j+1-c[i];
}
for(i=n;i>=1;i--){
Add(d[i]);
r[i]=Sum(d[i]-1);
}
for(i=1;i<=n;i++){
ans+=(long long)l[i]*(long long)r[i];
}
printf("%lld\n",ans);
return 0;
}