Lydsy1706月賽 大根堆 亂搞 啟發式合併

2021-08-27 16:17:40 字數 1831 閱讀 2790

description

給定一棵n個節點的有根樹,編號依次為1到n,其中1號點為根節點。每個點有乙個權值v_i。

你需要將這棵樹轉化成乙個大根堆。確切地說,你需要選擇盡可能多的節點,滿足大根堆的性質:對於任意兩個點i,j,如果i在樹上是j的祖先,那麼v_i>v_j。

請計算可選的最多的點數,注意這些點不必形成這棵樹的乙個連通子樹。

sample input

63 0

1 12 1

3 14 1

5 1sample output

5一開始一看,覺得這題是個樹上lis。

然後就想殘了,打了個主席樹。。。

發現諸多問題,於是跑去膜題解。

對於一棵子樹,考慮用set維護。

我們肯定希望集合中最後乙個元素盡量小。

每次當前節點合到屬於x的集合中去時,我們作如下操作:

尋找當前x值的lower_bound,將其刪除,然後將x插到set中去。

這樣對答案是沒有影響的,考慮小於當前x的值,顯然沒有影響,再考慮,後面的元素。

如果當前值的lower_bound為集合中最後乙個元素,顯然可用這個更小的值替換。

如果當前值的lower_bound不為集合中最後乙個元素,也就是說x暫時不能對答案構成更新,直到後面不斷利用x的值使得set結尾的值更小,這時x才能做出貢獻,顯然這樣是合法的,如:

當前數列1,2,3,9,10

這時x進入,值為4,數列變為:1,2,3,4,10

這時x的父親出現乙個5,數列變為:1,2,3,4,5

此時陣列結尾對比原來要小,並且此時可用x,x的父親,權值為1,2,3的節點構成一棵合法樹,故x的替換不造成影響。

注意還有乙個細節,將x的子節點y的set合到x上時,建議使用啟發式合併。

#include

#include

#include

#include

#define it multiset::iterator

using

namespace std;

int_max

(int x,

int y)

intread()

while

(ch >=

'0'&& ch <=

'9') s = s *

10+ ch -

'0', ch =

getchar()

;return s * f;

}struct edge e[

210000];

int len, last[

210000];

int a[

210000];

multiset<

int> q[

210000];

void

ins(

int x,

int y)

void

merge

(int x,

int y)

void

dfs(

int x)

it it = q[x]

.lower_bound

(a[x]);

if(it != q[x]

.end()

) q[x]

.erase

(it)

; q[x]

.insert

(a[x]);

}int

main()

dfs(1)

;printf

("%d\n"

, q[1]

.size()

);return0;

}

bzoj4919 Lydsy1706月賽 大根堆

給定一棵n個節點的有根樹,編號依次為1到n,其中1號點為根節點。每個點有乙個權值v i。你需要將這棵樹轉化成乙個大根堆。確切地說,你需要選擇盡可能多的節點,滿足大根堆的性質 對於任意兩個點i,j,如果i在樹上是j的祖先,那麼v i v j。請計算可選的最多的點數,注意這些點不必形成這棵樹的乙個連通子...

Lydsy月賽合輯

不想單開的就寫在這裡了 都還是挺不錯的啊 許可權題沒有 又是被ozy秒殺的我 不考慮嚴格大於的話你直接ai,bi取個max就過了 現在要考慮嚴格大於,相當於每個矩形,都是一條在ai,bi中的邊 我們定義這個數被作為一次長,當且僅當有一條新的邊指向了他 最後我們就要給所有邊定向,顯然要求每個數最多只有...

BZOJ4919 Lydsy六月月賽 大根堆

題解 我覺得資料結構寫成結構體還是有必要的 因為不然一道題裡出現了兩個相同的資料結構由於名字很像很容易出錯 另外初始化用segmenttree 首先裸的dp很好想 f i j 表示在i點,最大值 j的點數最大值 看了別人的題解知道了可以用線段樹合併來優化這個東西。我們考慮對於每個點,首先我們要合併它...