树状数组求逆序对

今天复习了一下树状数组,顺便学了一下如何求逆序对。

首先是树状数组单点修改+区间和,但有一点需要注意,就是getsum函数里是now-=lowbit(now),但是update()里或add()里一定是now += lowbit(now);

#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN = 1e5 + 5;
int n,c[MAXN],a[MAXN],m;
int lowbit(int x)
{
    return x & -x;
}
int getsum(int now)
{
    int sum = 0;
    while(now > 0)
    {
        sum += c[now];
        now -= lowbit(now);
    }
    return sum;
}
void update(int l,int v)
{
    while(l <= n)
    c[l] += v,l += lowbit(l);
}
/*int build_tree(int x)
{
    int ret = 0;
    while(x > 0)
    {
        ret += c[pos];
        pos -= lowbit(pos);
    }
    return ret;
}*/
int main()
{
    int c,d,e;
    cin>>n>>m;
    for(int i = 1;i <= n;i++)
    {
        cin>>a[i];
        update(i,a[i]);
    }
    for(int i = 1;i <= m;i++)
    {
        cin>>c>>d>>e;
        if(c == 1)
        {
            update(d,e);
        }
        else
        {
//            cout<<getsum(e)<<" "<<getsum(d - 1)<<endl;
            cout<<getsum(e) - getsum(d - 1)<<endl;
        }
    }
    return 0;
}

然后是区间修改+单点求值,和单点修改有不同,主要是一开始不把数放进数组,然后假如要把d~f区间加上n,就先把d之后的都加上,然后减去f+1之后的就行了。

#include<cstdio>
#include<iostream>
using namespace std;
const int MAXN = 1e7 + 5;
int n,c[MAXN],a[MAXN],m,input[MAXN],g;
int lowbit(int x)
{
    return x & -x;
}
int getsum(int now)
{
    int sum = 0;
    while(now > 0)
    {
        sum += c[now];
        now -= lowbit(now);
    }
    return sum;
}
void update(int l,int v)
{
    while(l <= n)
    c[l] += v,l += lowbit(l);
}
/*int build_tree(int x)
{
    int ret = 0;
    while(x > 0)
    {
        ret += c[pos];
        pos -= lowbit(pos);
    }
    return ret;
}*/
int main()
{
    int d,e,f;
    cin>>n>>m;
    for(int i = 1;i <= n;i++)
    {
        cin>>a[i];
//        update(i,a[i]);
    }
    for(int i = 1;i <= m;i++)
    {
        cin>>g;
        if(g == 1)
        {
            cin>>d>>e>>f;
            update(d,f);
            update(e + 1,-f);
        }
        else
        {
            cin>>d; 
            cout<<getsum(d) + a[d]<<endl;
        }
    }
    return 0;
}

最后,是求逆序对。先把这些数(结构体里再存一个编号)按照从大到小排序,(就算是离散化了,然后和原数就没关系了),然后向数组中插入编号,每次计算前面的和。注意,getsum里传入的是编号,而且必须传的是num-1.

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int c[40005],a[40005],n;
struct node{
    int k,c;
};
node d[40055];
int lowbit(int x)
{
    return x & -x;
}
int getsum(int now)
{
    int sum = 0;
    while(now > 0)
    {
        sum += c[now];
        now -= lowbit(now);
    }
    return sum;
}
int add(int now,int k)
{
    while(now < n)
    {
        c[now] += k;
        now += lowbit(now);
    }
}
bool cmp(node x,node y)
{
    return x.k > y.k;
}
int main()
{
    int ans = 0;
    cin>>n;
    for(int i = 1;i <= n;i++)
    {
        d[i].c = i;
        cin>>d[i].k;
    }
    sort(d + 1,d + n + 1,cmp);
    for(int i = 1;i <= n;i++)
    {
        add(d[i].c,1);
        ans += getsum(d[i].c - 1);
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/DukeLv/p/8955842.html