hdu1394(权值线段树求逆序数) Minimum Inversion Number

http://acm.hdu.edu.cn/showproblem.php?pid=1394

题目描述:

给定一个序列,每次左移一位,问得到的所有序列中最小的逆序数(序列中逆序对的数量)。

分析:用线段树维护数字出现的次数,每次插入一个树前,查询比他大的数个数,便是逆序数。

然后观察每次把开头移动到末尾后答案的变化。具体在代码解释:

代码:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<sstream>
#include<vector>
#include<stack>
#include<deque>
#include<cmath>
#include<map>
#include<queue>
#include<bitset>
#include<hash_map>
#define sd(x) scanf("%d",&x)
#define ms(x,y) memset(x,y,sizeof x)
#define fu(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define all(a) a.begin(),a.end()
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int maxn=5e4+79;
const int mod=998244353;
const int INF=1e9+7;
const double pi=acos(-1);
int t[maxn<<1],a[maxn];
void updata(int dis,int l,int r,int rt)
{
    if(l==r) 
    {
        //权值线段树,维护元素dis出现的次数
        t[rt]++;
        return;
    }
    int mid=(l+r)>>1;
    if(dis<=mid) updata(dis,lson);
    else updata(dis,rson);
    t[rt]=t[rt<<1]+t[rt<<1|1];
}
ll que(int L,int R,int l,int r,int rt)
{
    if(l>=L&&r<=R) return t[rt];
    int mid=(l+r)>>1;
    ll s=0;
    if(L<=mid) s+=que(L,R,lson);
    if(R>mid) s+=que(L,R,rson);
    return s;
}
int main()
{
    
    int n;
    while(~sd(n))
    {
        ms(t,0);
        ll ans=0;
        fu(i,1,n)
        {
            sd(a[i]);a[i]++;//变成1~n的排列
            //找原来序列的逆序
            ans+=que(a[i],n,1,n,1);//每次插入找比a[i]大的数个数,就是逆序数
            updata(a[i],1,n,1);//插入该点
        }
        ll res=ans;
        fu(i,1,n)
        {
            /*
            a[i]是枚举开头的数字,把他放末尾发生的变化如下:
            1.之前他后面所有比他小的数字与他构成的逆序没了。
            2.他后面所有比他大的数字在他到末尾后构成逆序。
            */
            res-=que(1,a[i],1,n,1)-1;//减1是把自己减出来
            res+=que(a[i],n,1,n,1)-1;
            /*
            因为这题是一个排列,所以所有数字都出现一次,
            也可以直接减去,如下
            res-=a[i]-1;
            res+=n-a[i];
            */
            ans=min(ans,res);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

posted on 2020-08-05 15:37  Aminers  阅读(82)  评论(0编辑  收藏  举报

导航