树状数组:求比a小在a前面数数量和比a小在a后面数数量的思路

求比a小在a前面数数量和比a小在a后面数数量的思路:

在看之前,你必须了解树状数组的基本函数

inline ll lowbit(ll x)
{
    return x&(-x);
}
inline void insert(ll x,ll y)//加入 
{
    while(x<=n)
    {
        sum[x]+=y;
        x+=lowbit(x);
    }
}
inline ll findout(ll x)//查找 
{
    ll ans=0;
    while(x)
    {
        ans+=sum[x];
        x-=lowbit(x);
    }
    return ans;
}
inline ll cmp(oh a,oh b)//排序 
{
    if(a.v==b.v)
        return a.num<b.num;
    else
        return a.v<b.v;
}

求有多少在a前面的数比a小

首先,假如求有多少在a前面的数比a小;

举例:                  1 4 2 3 5

然后有5个空位置, _ _ _ _ _ 为sum[5]

第一步     求出sum[1]前缀,答案是0;

                插入1,  1 _ _ _ _

第二步     求出sum[4]前缀,答案是1;

                插入4,  1 _ _ 4 _

第二步     求出sum[2]前缀,答案是1;

                插入4,  1 2 _ 4 _

..........................

这样不断进行下去sum[i]就是 有多少在i前面的数比a小;

所以就转化成了求前缀和的题目了,自然就想到树状数组了;

但是输入的几个数可能会非常大,那么sum数组的下标就会爆;

我们只需知道每个数的大小关系,并不需要知道具体值,所以在处理之前可以离散化;

    //离散化 
    for(ll i=1;i<=n;i++)
    {
        a[i].v=read();
        a[i].num=i;//将每一个数的位置记下 
    }
    sort(a+1,a+n+1,cmp);//从小到大排序,
                        //这样每个数都有顺序了,并且每个数对应的位置没有改变 
    for(ll i=1;i<=n;i++)
        b[a[i].num]=i;//把第i小的数位置上赋值为i 

具体怎么实现,读者自行手动模拟;

按上面查找的思路

    for(ll i=1;i<=n;i++)
    {
        ll x=findout(b[i]);
        ans[i]=x;//先求值,再插入,不然会把自己也算进去的 
        insert(b[i],1);
    }

那么求比a小在a后面数数量

则反之

    for(ll i=n;i>=1;i--)
    {
        ll x=findout(b[i]);
        ans[i]=x;//反之 
        insert(b[i],1);
    }

这样就ok了

猜你喜欢

转载自www.cnblogs.com/wzx-RS-STHN/p/13193271.html