题目:点击打开链接
题意:给定一个数列,求出多少组满足条件的数,使得下标i<j<k且ai>aj>ak
分析:很显然,这题需要用树状数组做,先离散化,定义数组s1表示当前已经加入的数,数组s2表示当前加入的数的先前的s1之和,从后往前加入每个数,因为满足题意的数一定是大于前面的某个数,所以当加入到s1时找到前面的s1之和,即为有多少比该数小的数,将个数赋值为s2的该数的值,此时统计比该数小的数的s2值之和,将该和累加到答案中,具体可以举例感受。
代码:
#include <stdio.h>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define sqr(x) ((x)*(x))
#define ll long long
#define ull unsigned __int64
const ll INF = 1e18;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=1000100;
const int MOD=100000;
const double eps=1e-10;
const double pi=acos(-1.0);
using namespace std;
int n;
int a[N],t[N];
ll s1[N],s2[N];
void add(ll *s,int x,int v)
{
for(int i=x;i<=n;i+=i&(-i))
s[i]+=v;
}
ll query(ll *s,int x)
{
ll ans=0;
for(int i=x;i;i-=i&(-i))
ans+=s[i];
return ans;
}
int main()
{
int i;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
t[i]=a[i];
}
sort(t+1,t+1+n);
int m=unique(t+1,t+1+n)-t-1;
for(i=1;i<=n;i++)
a[i]=lower_bound(t+1,t+1+n,a[i])-t;
add(s1,a[n],1);
ll ans=0,sum=0;
for(i=n-1;i>0;i--)
{
sum=query(s1,a[i]-1);
add(s1,a[i],1);
add(s2,a[i],sum);
ans+=query(s2,a[i]-1);
}
printf("%I64d\n",ans);
}