HDU - 1394(权值线段树)

本题就是求逆序对,因为数据范围比较小,可以不用离散化,直接用权值线段树就可以了

权值线段树就是在线段树里记录每个数出现的次数,而不是记录位置+值,

#include <bits/stdc++.h>
using namespace std;
const int maxn = 5000+10;
int num[maxn << 2 + 10];
int a[maxn];
void push_up(int i)
{
    num[i]=num[i<<1] + num[i<<1|1];
}
void build(int l , int r , int i)
{
    num[i] = 0;
    if(l == r){return;}
    int mid = (l+r) >>1 ;
    build(l,mid,i<<1);
    build(mid+1,r,i<<1|1);
}

int query(int L , int R , int l , int r , int i)
{
//    cout << L << " --- " << R << endl;
    if(L >= l&& R <= r)
    {
        return num[i];
    }
    int mid = (L + R) >> 1;
    if(mid >= r)
    {
        return query(L , mid , l,r,i << 1 );
    }
    else if(mid < l)
    {
        return query(mid + 1 , R , l,r,i << 1 | 1);
    }
    else
    {
        return query(L , mid , l,r,i << 1 ) + query(mid + 1 , R , l,r,i << 1 | 1);
    }
}

void update(int L , int R , int i , int x)
{
    if(L == x && L == R)
    {
        num[i]++;
        return ;
    }
    int mid = (L + R) >> 1;
    if(mid >= x)
    {
        update(L , mid , i << 1 , x);
    }
    else if(mid < x)
    {
        update(mid + 1 ,R, i << 1 | 1 , x);
    }
    push_up(i);
}
int main()
{
    int n;
    while(cin>>n)
    {
        build(1,n,1);
        int ans=0,x;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            a[i]++;
            ans+=(query(1,n,a[i],n,1) - query(1,n,a[i],a[i],1));
//            cout << " 0---0" <<endl;
            update(1,n,1,a[i]);
        }
        int sum=ans;
//        cout << sum << "  --" << endl;
        for(int i=n-1;i>=0;i--)
        {
            ans=ans-(n-a[i])+(a[i]-1);
            sum=min(sum,ans);
        }
        cout<<sum<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/zhaiqiming2010/article/details/81153456
今日推荐