hdu 1394 線段樹求逆序數

2021-06-17 17:20:25 字數 1588 閱讀 6444

/*  

線段樹求逆序數   求小逆序數   神奇

題意:給定乙個序列,對該序列的n種排列(排列如下)的每種排列(0 ~ n-1)的逆序數求最小值:

a1, a2, ..., an-1, an  

a2, a3, ..., an, a1  

a3, a4, ..., an, a1, a2  

...  

an, a1, a2, ..., an-1

思路:先求出初始序列的逆序數,可以歸併,這裡用的是線段數求。

設當前逆序數為sum,則每次把第乙個數x移到最後,則新序列的逆序數 = sum - x + (n - 1 - x)

sum = sum - a[i] + (n - 1 - a[i]);      //太神奇了,這個轉移方程.

前面部分用線段樹求初始逆序簡單說一下,就是先建一棵樹,每個節點[l,r]儲存乙個sum值,表示到目前為止[l,r]出現的個數。如當前序列為1,3, 則節點[0,3].sum = 2, [0, 4].sum = 2。然後每次掃到乙個新的數x都先詢問舊序列中[x+1, n-1]中出現的個數...

*** 逐個插入值(即輸入的乙個值);  在每插入乙個值後就更新包含該區間的所有的數的個數(加一)****/

#include #include using namespace std;

#define debug printf("!\n")

#define maxn 5005

#define l(x) ((x)<<1)

#define r(x) (((x)<<1)|1)

#define mid(x, y) (((x)+(y))>>1)

int a[maxn], pos[maxn], high[maxn];

struct node f[maxn * 3];

int n;

void update(int root)

int query(int root, int l, int r)

int mid = mid(f[root].l, f[root].r);

if(r <= mid) return query(l(root), l, r);

else if(mid < l) return query(r(root), l, r);

else return query(l(root), l, mid) + query(r(root), mid+1, r);

}void build(int root, int l, int r)

int mid = mid(l, r);

build(l(root), l, mid);

build(r(root), mid+1, r);

}int main()

int sum = 0;

for(int i = 0; i < n; i++) sum += high[i];

int ans = sum;

for(int i = 0; i < n; i++)

printf("%d\n", ans);

}}

hdu1394線段樹求逆序數

這個吧,就是這麼回事。你把每乙個數都插在相應的點上。然後,query來計算a i 道n的插得點個數,因為你是按順序插得。先插的而且還在後面。那麼一定構成逆序數。然後用sum儲存一下。還有逆序數的計算第乙個數放到最後,比他小的有x 1個,比他大的有n x個。然後給移到後面,逆序數增加n x 個,比x小...

hdu1394 線段樹求逆序數

題意 給出一串數字a,可以進行如下操作 將該串數字第乙個數字a0放到該串數字的最後位置,形成新的數字串,求操作過程中最小逆序數。思路1 求一串數字的逆序數 暴力法 對每乙個數字x,判斷x與x之前出現了多少個比x大的數字。複雜度為o nn 利用線段樹 因為數字串出現的數字只能在區間0 n,可以利用線段...

hdu 1394 求逆序數(線段樹求)

題意描述 給你乙個有0 n 1數字組成的序列,然後進行這樣的操作,每次將最前面乙個元素放到最後面去會得到乙個序列,那麼這樣就形成了n個序列,那麼每個序列都有乙個逆序數,找出其中最小的乙個輸出!解析 求出a1,a2,an 1,an的逆序數之後,就可以遞推求出其他序列的逆序數。假設要把a1移動到an之後...