HDU 1394(线段树单点更新)

来源:互联网 发布:日本药妆 知乎 编辑:程序博客网 时间:2024/05/23 02:03

题意:就是给出一串数,当依次在将第一个数变为最后一个数的过程中,要你求它的最小逆序数。

思路:可以用树状数组和线段数做。这里我是用线段树做的。建的是一棵空树,然后每插入一个点之前,统计大于这个数的有多少个,直到所有的数都插入完成,就结果了逆序树的统计。

要得出答案主要是利用了一个结论,如果是0到n的排列,那么如果把第一个数放到最后,对于这个数列,逆序数是减少a[i],而增加n-1-a[i]的.

#include<iostream>#include<cstring>#include<cstdio>#include<string>#include<algorithm>#include<cmath>#include<map>#include<vector>#include<queue>#define INF 0x3fffffff#define MAXN 5001#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1using namespace std;int sum[MAXN<<2];int a[MAXN];void pushup(int rt){    sum[rt]=sum[rt<<1]+sum[rt<<1|1];}void build(int l,int r,int rt){    sum[rt]=0;    if(l==r)        return;    int m=(r+l)>>1;    build(lson);    build(rson);}void update(int p,int add,int l,int r,int rt){    if(l==r)    {        sum[rt]+=1;        return;    }    int m=(l+r)>>1;    if(p<=m)        update(p,add,lson);    else        update(p,add,rson);    pushup(rt);}int query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R)        return sum[rt];    int m=(l+r)>>1;    int ret=0;    if(L<=m) ret+=query(L,R,lson);    if(R>m) ret+=query(L,R,rson);    return ret;}int main(){    int n;    while(scanf("%d",&n)!=EOF)    {        int ans=0;        build(0,n-1,1);        for(int i=0;i<n;i++)        {            scanf("%d",a+i);            ans+=query(a[i]+1,n-1,0,n-1,1);            update(a[i],1,0,n-1,1);        }        int minn=ans;        for(int i=0;i<n-1;i++)        {            ans=ans-a[i]+(n-a[i]-1);            if(ans<minn)                minn=ans;        }        printf("%d\n",minn);    }    return 0;}


0 0
原创粉丝点击