Codevs 1282 約瑟夫問題 線段樹

2021-07-23 15:20:54 字數 1370 閱讀 7885

codevs 1282 約瑟夫問題

首先,建樹,根節點 l = 1, r = n, sum = n;

sum 指的是在這個區間內 還剩下的人數。

主函式乙個 while 迴圈, 一直迴圈到根節點 為 0; 也就是所有人都出圈了。

另外:根節點的sum (tree[1].sum)代表還沒出圈的還有多少人。

我們可以將 圓圈看為乙個佇列,最後乙個人的後面是 1、

nxt 為 從當前點往後 m 個人之後(可能到了尾部又從1開始)第 nxt個人。並不是 編號為 nxt 的人。

比如:

現在隊列為 1 3 5 7。

2、4、6出圈了。

如果我nxt = 2, 那麼我指的是從佇列頭 開始往後2個人, 就是編號為3 的人。

搞清楚了這一點之後開始考慮如何找 當前佇列中第 nxt 個人。

利用change 操作, 從線段樹根節點往下走, 因為我們找的是 第 nxt 個人,所以,如果左邊節點裡面的人數 小於 nxt 那麼我們要找的人肯定在右邊節點。 就變成了 找右邊節點中的第 nxt - x 個人。 另外,我們走過的節點的 sum 需要–, 因為我們已經確定我們要找的人 在這個區間裡面了, 我們找到之後 另 這個人的 sum = 0; 表示沒有這個人了。 也可以 – , 反正這是最底層節點, sum = 1;

再利用change 返回我們找到的這個點的編號,就行了。

**:

#include 

#include

#include

#include

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

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

using namespace std;

const int maxn = 30000 + 3;

int n, m;

struct ttree[maxn << 2];

void update(int p)

void build(int l, int r, int p)

int mid = (l+r)/2;

build(l,mid,l(p));

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

update(p);

return;

}int change(int x, int p = 1)

if(tree[l(p)].sum >= x)

return change(x,l(p));

else

return change(x-tree[l(p)].sum, r(p));

}int main()

return

0;}

Codevs 1282 約瑟夫問題

1282 約瑟夫問題 時間限制 1 s 空間限制 128000 kb 題目描述 description 有編號從1到n的n個小朋友在玩一種出圈的遊戲。開始時n個小朋友圍成一圈,編號為i 1的小朋友站在編號為i小朋友左邊。編號為1的小朋友站在編號為n的小朋友左邊。首先編號為1的小朋友開始報數,接著站在...

Codevs 1282 約瑟夫問題

時間限制 1 s 空間限制 128000 kb 題目等級 大師 master 有編號從1到n的n個小朋友在玩一種出圈的遊戲。開始時n個小朋友圍成一圈,編號為i 1的小朋友站在編號為i小朋友左邊。編號為1的小朋友站在編號為n的小朋友左邊。首先編號為1的小朋友開始報數,接著站在左邊的小朋友順序報數,直到...

wikioi 1282 約瑟夫問題

這道題所用到的資料結構應該是名次樹,名次樹可以由線段樹實現也可以由樹狀陣列實現。而對於類似這道題這樣的乙個只需要刪除和查詢操作的名次樹而言,可以用樹狀陣列實現,因為用樹狀陣列實現無論效率還是 複雜度都較線段樹而言更優,雖然演算法較線段樹而言更加巧妙。首先,這個資料結構需要乙個用於查詢第k名是什麼的函...