一. 题目

image.png

二. 理论

  • image-glnw.pngimage-aalg.pngimage-pwsk.png

  • 树状数组结构分析

  • 上面时树状数组的结构图,t[x]保存以x为根的子数中叶子节点值的和,原数组为a[]那么原数组前4项的和t[4]=t[2]+t[3]+a[4]=t[1]+a[2]+t[3]+a[4]=a[1]+a[2]+a[3]+a[4],看似没有什么特点,别着急往下看

  • 我们通过观察节点的二进制数,进一步发现,树状数组中节点x的父节点为x+lowbit(x),例如t[2]的父节点为t[4]=t[2+lowbit(2)]


  • 本题思路

  • 从左往右遍历,y值作为下标,在其下标处加1,表示这个值出现过,利用树状数组统计下对于第i个数左边有多少比他小的,比他大的。左边比i小的就是getSum(a[i]-1),左边比他大的就是当前总数减<=a[i]的,getSum(n)-getSum(a[i])

  • 从右往左遍历,右边有多少比他小的,比他大的即可。右边比他小的就是getSum(a[i]-1), 右边比他大的是getSum(n)-getSum(a[i])

  • 最后组合数学,相乘统计即可

三. 代码

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
using namespace std;
const int N=2e5+10;
using LL=long long;

int n;
int a[N];

class TreeArray
{
public:
    int tr[N];
public:
    TreeArray()
    {
        initIO();
        init();
    }

    void init()
    {
        fill(tr, tr+N, 0);
    }

    void initIO()
    {
        ios::sync_with_stdio(false);
        cin.tie(nullptr), cout.tie(nullptr);
    }

    //返回x的最后一位1
    int lowbit(int x)
    {
        return x&-x;
    }

    void add(int x, int v)
    {
        for(int i=x;i<=n;i+=lowbit(i))
            tr[i]+=v;
    }

    //得到从1~x这段的和
    int getSum(int x)
    {
        int sum=0;
        for(int i=x;i;i-= lowbit(i))
            sum+=tr[i];
        return sum;
    }

    //得到区间和,利用前缀和思想
    int getLRV(int l, int r)
    {
        return getSum(r)-getSum(l-1);
    }
}ta;

class Info
{
public:
    int lmin, lmax;//左边比当前小的大的数量
    int rmin, rmax;//右边比当前小的大的数量
public:
    Info()
    {
        lmin=lmax=rmin=rmax=0;
    }
}info[N];

int main()
{
    cin>>n;
    for(int i=1;i<=n;++i)
    {
        cin>>a[i], ta.add(a[i], 1);
        info[i].lmin=ta.getSum(a[i]-1);
        info[i].lmax=ta.getLRV(a[i]+1, n);
    }

    ta.init();
    for(int i=n;i;--i)
    {
        ta.add(a[i], 1);
        info[i].rmin=ta.getSum(a[i]-1);
        info[i].rmax=ta.getLRV(a[i]+1, n);
    }

    LL ansA=0, ansT=0;
    for(int i=1;i<=n;++i)
    {
        ansA+=1ll*info[i].lmax*info[i].rmax;
        ansT+=1ll*info[i].lmin*info[i].rmin;
    }
    cout<<ansA<<" "<<ansT;
}