HDU 1394 树状数组||线段树

来源:互联网 发布:远洋数据工资怎么样 编辑:程序博客网 时间:2024/05/16 11:33

给出一个序列,from 0 to n-1,如果2个数满足下标小的值大,那么逆序数的和+1

可以把最左边的数 放到最右边,按此规则变换,求过程中产生的最小的逆序数的和

思路

先求出原始序列的逆序数的和,然后如果每次移动最左边的数到最右边,那么逆序数的变化是可以预知的 

因为由于最左边的数产生的逆序数 为他右边比他小的数个数,而除了他自己,剩下的数都在他右边,一共n-1个,比他小的数的个数就是str[i];

而最左边的数放到最右边所新产生的逆序数也是可以预知的,为(把最左边放到最右边之后)他左边比他大的数,一共n-1个,比他大的个数是n-1-str[i];

求原始序列的时候,只需要统计一下在这个数之前出现过的比他小的数的个数x,那么他后面比他小的个数即str[i]-x;

树状数组 和线段树都可以很方便的统计出x.

需要注意的就是 数字的值从0到n-1;


线段树版...算是第一个纯手写的>_<了

单点更新+区间查询

#include<stdio.h>#define lson l,mid,rt<<1#define rson mid+1,r,rt<<1|1#include<string.h>#include<algorithm>using namespace std;int sum[5005<<2];void pushUP(int rt){    sum[rt]=sum[rt<<1]+sum[rt<<1|1];}int query(int L,int R,int l,int r,int rt){    if(L<=l&&r<=R){        return sum[rt];    }    int mid=(l+r)>>1;    int sum=0;    if(L<=mid)sum+=query(L,R,lson);    if(mid<R)sum+=query(L,R,rson);    return sum;}void update(int x,int l,int r,int rt){    if(l==r){        sum[rt]++;        return ;    }    int mid=(l+r)>>1;    if(x<=mid)update(x,lson);    if(x>mid)update(x,rson);    pushUP(rt);}int str[5005];int main(){    int n,tp,ans;    while(scanf("%d",&n)!=EOF){        tp=ans=0;         memset(sum,0,sizeof(sum));        for(int i=0;i<n;i++){             scanf("%d",&str[i]);             tp+=str[i]-query(0,str[i],0,n-1,1);             update(str[i],0,n-1,1);        }ans=tp;        for(int i=0;i<n;i++){            tp=tp-str[i]+(n-1-str[i]);            ans=min(tp,ans);        }printf("%d\n",ans);    }return 0;}


树状数组 要注意 str[i]值要+1,因为无法处理=0的状况

#include<stdio.h>#include<string.h>#include<algorithm>using namespace std;int c[5005],n;int lowbit(int x){    return -x&x;}int get(int x){    int ans=0;    while(x>0){        ans+=c[x],x-=lowbit(x);    }return ans;}void add(int x,int d){    while(x<=n){        c[x]+=d,x+=lowbit(x);    }}int main(){    int str[5005],tp;    while(scanf("%d",&n)!=EOF){        tp=0;        memset(c,0,sizeof(c));        for(int i=0;i<n;i++){            scanf("%d",&str[i]);            str[i]++;            tp+=i-get(str[i]);            add(str[i],1);        }int ans=tp;        for(int i=0;i<n;i++){            tp=tp-str[i]+1+(n-str[i]);            ans=min(tp,ans);        }        printf("%d\n",ans);    }return 0;}



原创粉丝点击