計蒜客 青出於藍勝於藍 dfs 樹狀陣列

2021-09-05 13:12:27 字數 2180 閱讀 7976

題目描述: 

武當派一共有 n人,門派內 n 人按照武功高低進行排名,武功最高的人排名第 1,次高的人排名第 2,... 武功最低的人排名第 n。現在我們用武功的排名來給每個人標號,除了祖師爺,每個人都有乙個**,每個人可能有多個徒弟。

我們知道,武當派人才輩出,連祖師爺的武功都只能排行到 p。也就是說徒弟的武功是可能超過**的,所謂的青出於藍勝於藍。

請你幫忙計算每個人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟....)中,有多少人的武功超過了他自己。

輸入格式

輸入第一行兩個整數 n,p(1≤n≤100000,1≤p≤n)n, p(1 <= n <= 100000, 1 <= p <= n)n,p(1≤n≤100000,1≤p≤n)。

接下來 n−1n-1n−1 行,每行輸入兩個整數 u,v(1≤u,v≤n)u, v(1 <= u, v <= n)u,v(1≤u,v≤n),表示 u 和 v 之間存在師徒關係。

輸出格式

輸出一行 n 個整數,第 i 個整數表示武功排行為 i 的人的子弟有多少人超過了他。

行末不要輸出多餘的空格。

樣例輸入

10 5

5 35 8

3 43 1

2 16 7

8 79 8

8 10

樣例輸出

0 0 2 0 4 0 1 2 0 0

題解參考

題解:

如下圖所示,對一顆樹進行dfs,先搜尋自己,然後是所有孩子節點。(以二叉樹為例)

節點旁邊的編號表示搜尋的時序,從根節點開始搜,第一次搜的是1節點,然後搜2、4、8、5.....(圖上只標註了一部分)

對於節點2來說,其子節點為搜尋時序3,4,5的節點。

所以dfs的時候,每搜尋到乙個節點時,使用陣列l標記其搜尋時序,將子節點搜尋完後,r陣列標記回溯時的時序,這樣就可以判斷每個節點子節點的搜尋時序範圍。比如對2來說,dfs時序為2,搜完子節點回溯時時序為5,所以3-5時序的就是其子節點。

題目要求每乙個節點子節點比自己小的個數,所以就可以將節點從1-n遍歷,每次計算區間l[i]-r[i]的區間和sum(sum表示區間內比當前節點小的節點數),l[i]-r[i]區間就確保一定是i節點的子節點,因為要統計的節點一定比i小,所以每次遍歷乙個節點時,就將其時序l[i]的地方加1,這樣後面求區間和時如果包含了之前加1的部分,那就可以統計進去。。(說得有點繞,具體看**)

// 從1開始計數

int c[maxn]; // 樹狀陣列

int head[maxn];// i號節點的第乙個子節點在結構體陣列的下標為head[i]

int l[maxn],r[maxn];// l陣列:記錄dfs搜到i點時的次序,r陣列:記錄dfs回溯回i點時的時序

int n,f;// 輸入

int times;// 深度搜尋的次序

struct node node[maxn];

int num;// node陣列元素數目

// 取x最低位的1

int lowbit(int x)

// pos下標處增加delta

void update(int pos,int delta)

}// 區間查詢,查詢前x項和

int query(int x)

return cnt;

}// 往圖里加點

void add(int u,int v)

// 深度優先搜尋,先搜完孩子節點,再搜本節點

// cur:當前節點編號,father: 父節點編號(用來避免重複搜尋)

void dfs(int cur,int father)

// 回溯時標記

r[cur] = times;

}int main()

dfs(f,-1);// 從根節點開始搜尋

// 從第一名到最後一名遍歷武林高手

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

return 0;

}

計蒜客 青出於藍勝於藍 dfs序 歸併樹

武當派一共有 nn 人,門派內 nn 人按照武功高低進行排名,武功最高的人排名第 11,次高的人排名第 22,武功最低的人排名第 nn。現在我們用武功的排名來給每個人標號,除了祖師爺,每個人都有乙個 每個人可能有多個徒弟。我們知道,武當派人才輩出,連祖師爺的武功都只能排行到 pp。也就是說徒弟的武功...

計蒜客 2019計蒜之道D

題意 現在給定你乙個字串 s ss 以及乙個整數 k kk,請求出 s ss的字典序最小的長度為 k kk的子串行。資料範圍 0 s 5000000 00 s 5000 000 樣例輸入 helloworld 5樣例輸出 ellld思路 假如我們先不考慮長度為k的限制我們應當怎麼做?我們以樣例為例子...

計蒜客 解碼

蒜頭君自己發明了一種字串的編碼方式,對於只含有大小寫字母的字串,可以用數字來表示括號裡面的串連續出現的次數 數字有可能超過一位數 比如a abcd 2等價於aabcdabcd。特別地,如果數字前面沒有括號,表示緊貼數字的前面的 乙個字母 出現的次數。比如abc2表示abcc。為了降低解碼的難度,蒜頭...