poj 2182 線段樹 樹狀陣列

2021-09-08 22:20:45 字數 3238 閱讀 8586

題目大意

n個數排成一排(不知道大小,只是佔了乙個位置),從a[1]到a[n]進行遍歷,對於每個a[i],給出從a[1]到a[i-1]中小於a[i]數的個數。要求出 a[1]到a[n]中這n個數的相對順序。

題目分析

則 a[i] 在所有n個數中的序號(按照從小到大排序)為 k = less[i] + t + 1

但是,t並不好直接求出,則觀察k的性質。對於a[i]在所有n個數中的位置k,1---k-1中包括 less[i]個在 a[1] -- a[i-1]中的元素,同時包括t個在a[i+1]---a[n]中的元素,在a[i+1]---a[n]中的元素已經確定了他們在整個n個數中的位置(我們是從後往前進行計算的),則 1----k-1中就可以確定那t個元素的位置。

為了確定k的位置,則設定乙個陣列b[1]--b[n],初始全部為0,從n到1統計,若a[i]的位置確定下來為p,則 b[p] = 1.則對於任意的k,b[1]---b[k]中1的個數表示 1----k中被占用的位置,0 的位置表示未被占用的位置。

對於 a[i],找到某個k,使得其b[1]--b[k-1]中0的個數正好為 less[i]個,則k的位置就是 a[i]在整個n個數中的按照大小排序的位置

實現(c++)

1. 線段樹

#define _crt_secure_no_warnings

#include#include#define max_cow_num 80010

#define max_node_num 4*max_cow_num

int gless[max_cow_num];

int gpos[max_cow_num];

struct node

};node gnodes[max_node_num];

void buildtree(int beg, int end, int index)

int left = 2 * index + 1;

int right = 2 * index + 2;

int mid = (beg + end) >> 1;

buildtree(beg, mid, left);

buildtree(mid + 1, end, right);

gnodes[index].sum_zero = gnodes[left].sum_zero + gnodes[right].sum_zero;

}//對於每個數 a[i], 給出了從 a[1] -- a[i-1]中小於a[i]的個數 less[i].

//從n到1逆序檢視, less[n] 表示前n-1個數中小於a[n]的個數,則可以確定a[n]的位置為 less[n] + 1

//類似的對於 i,為了確定a[i]在所有n個數中的序號,將這個任務分為兩部分:

//(1)在 a[1] -- a[i-1]中有多少個數小於a[i], 題目給出了為 less[i]

//(2)在a[i+1]---a[n]中有多少個數小於 a[i], 設為t

//則 a[i] 在所有n個數中的序號(按照從小到大排序)為 k = less[i] + t + 1

//t 並不好直接求出,則觀察k的性質。對於a[i]在所有n個數中的位置k,1---k-1中包括 less[i]個在 a[1] -- a[i-1]中的元素,

//同時包括 t個在a[i+1]---a[n]中的元素,在a[i+1]---a[n]中的元素已經確定了他們在整個n個數中的位置(我們是從後往前進行計算的),

//則 1----k-1中就可以確定那t個元素的位置。

//為了確定k的位置,則設定乙個陣列 b[1]--b[n],初始全部為0,從n到1統計,若a[i]的位置確定下來為p,則 b[p] = 1.

//則對於任意的k,b[1]---b[k]中1的個數表示 1----k中被占用的位置,0 的位置表示未被占用的位置。

//對於 a[i],找到某個k,使得其b[1]--b[k-1]中0的個數正好為 less[i]個,則k的位置就是 a[i]在整個n個數中的按照大小排序的位置

//利用線段樹,找到 b[1]---b[pos]中 0的個數為k個的pos的位置

void findkth(int k, int index, int& pos)

if (gnodes[index].beg == gnodes[index].end)

int left = 2 * index + 1, right = 2 * index + 2;

gnodes[index].sum_zero--;

if (gnodes[left].sum_zero >= k)

else

}int main()

int pos = 0;

gless[1] = 0;

for (int i = n; i >= 1; i--)

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

return 0;

}

2. 樹狀陣列

#define _crt_secure_no_warnings

#include#include#include#define max_cow_num 80010

int glowbit[max_cow_num];

int gc[max_cow_num];

int gless[max_cow_num];

int gpos[max_cow_num];

bool gused[max_cow_num];

void initlowbit(int n)

}void initsequence(int n)

}//樹狀陣列的更新

void update(int p, int n, int add)

}//樹狀陣列的查詢

int query(int p)

return result;

}//二分法,查詢滿足要求的 位置

int search(int k, int n)

return mid + 1;

} else if (sum_zero < k)

else

} return 1;

}int main()

for (int i = n; i >= 1; i--)

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

return 0;

}

poj 2182 樹狀陣列

這題對於o n 2 的演算法有很多,我這隨便貼乙個爛的,跑了375ms。include include using namespace std int mat 8008 int main for i 0 i printf d n mat i return0 view code 還是來看樹狀陣列的解法...

poj2182 樹狀陣列 二分)

題意 給乙個數n,然後n 1行,每行乙個數q,第i個數qi代表第i 1頭牛前面有qi頭牛編號比它小,求所有牛的編號。因為只有最後一頭牛編號是確定的,所有從後往前,每次用二分找到數字,並用樹狀陣列確定和儲存。include include include includeusing namespace ...

poj 2182 單點修改

題意 有n頭牛,標號從1到n,現在牛排成乙個佇列,知道每個牛的前面比自己標號小的牛的數量,輸出每個牛的標號。題解 給出的序列的最後乙個數字是可以推出的,然後把這個數字拿走,又能知道前面有幾個數字,和之前做過的有幾個空位乙個道理,維護線段樹區間解決。include include include us...