hdu 1394 線段樹單點更新

hdu 1394


題意:

有一個序列,a1,a2,.......,an,現在要使該序列經如下變換:

a1, a2, ..., an-1, an (where m = 0 - the initial seqence)

a2, a3, ..., an, a1 (where m = 1)

a3, a4, ..., an, a1, a2 (where m = 2)

...

an, a1, a2, ..., an-1 (where m = n-1)

求在該變換中逆序對數總和最小值。

解題思路:

我們可以先用線段樹來求最初的序列 a1,a2,a3,……,an每個數的逆序對數....首先我們可以將a1到an依次插入到線段樹中,按他們的數值插入到線段樹對應的位置,並使對應的線段樹的結點變爲1,在向上更新,然後只要判斷在   1~當前插入數-1區間內有多少已經插入的,則可以得到,有多少小於當前插入的數已經插入,即可得該數的逆序數。

通過上述操作,我們可以得到每個數的逆序數,和當前序列的逆序總數,所以當我們推到下一個序列時,且此時ai爲開頭,所以將ai放入最後時,新的逆序總數爲 原逆序總數 - ai + n -1 -  ai  


注意:

注意序列下標與線段樹下標對應






#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXN0 5005
#define l1(x) (x)<<1
#define r1(x) (x)>>1
struct TRnode{
    int L,R,sum;
};
TRnode TR[MAXN0<<2];
int nx[MAXN0];
int a[MAXN0];
void buildTR(int L,int R,int k){
    TR[k].L = L;
    TR[k].R = R;
    TR[k].sum = 0;
    if(L==R){
        return;
    }
    int mid = r1(L+R);
    int k1,k11;
    k1 = l1(k);
    k11 = k1 + 1;
    buildTR(L,mid,k1);
    buildTR(mid+1,R,k11);
}
int query(int L,int R,int k){
    if(R<L)return 0;
    if(TR[k].L==L&&TR[k].R==R){
        return TR[k].sum;
    }
    int mid = r1(TR[k].L+TR[k].R),k1,k11;
    k1 = l1(k);
    k11 = k1 + 1 ;
    if(mid>=R){
        return query(L,R,k1);
    }
    else if(mid<L){
        return  query(L,R,k11);
    }
    else {
        return  query(L,mid,k1)+query(mid+1,R,k11);
    }
}
void pu(int k,int k1,int k11){
    TR[k].sum = TR[k1].sum + TR[k11].sum;
}
void update(int num,int k){
    if(TR[k].L==TR[k].R){
        TR[k].sum = 1;
        return;
    }
    int mid = r1(TR[k].L+TR[k].R);
    int k1,k11;
    k1 = l1(k);
    k11 = k1 + 1;
    if(mid>=num){
        update(num,k1);
    }
    else {
        update(num,k11);
    }
    pu(k,k1,k11);
}
int main(){
    int n,num,ans,sumnx;
    while(scanf("%d",&n)!=EOF){
        buildTR(1,n,1);
        sumnx = 0;
        for(int i=0;i<n;++i){
            scanf("%d",&num);
            a[i] = num;
            nx[i] = num - query(1,num,1);
            sumnx+=nx[i];
            update(num+1,1);
        }
        int ans = sumnx;
        int up = n - 1;
        int tmp,tmp1 = 0,tmp2;
        tmp2 = n-1;
        for(int i=0;i<up;++i){
            sumnx = sumnx - a[i]+up - a[i];
            if(sumnx<ans)
                ans = sumnx;
            //--tmp;
            //tmp2 += (up-i);
        }
        printf("%d\n",ans);
    }
    return 0;
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章