給定一棵n個節點的有根樹,編號依次為1到n,其中1號點為根節點。每個點有乙個權值v_i。
你需要將這棵樹轉化成乙個大根堆。確切地說,你需要選擇盡可能多的節點,滿足大根堆的性質:對於任意兩個點i,j,如果i在樹上是j的祖先,那麼v_i>v_j。
請計算可選的最多的點數,注意這些點不必形成這棵樹的乙個連通子樹。
由於點不需要相鄰,此題其實是樹上的lis,從葉子節點向根節點形成lis
考慮lis的\(o(nlogn)\)演算法中用到的陣列,用multiset對每個節點維護這樣乙個陣列,儲存子樹內的值
向上的同時合併兩個multiset,用啟發式合併
時間複雜度應該是\(o(nlog^2n)\)
#include#include#include#include#define maxn 200005
using namespace std;
int n;
struct edgee[maxn<<1];
int head[maxn];
int sz;
void add_edge(int u,int v)
int a[maxn];
multisets[maxn];
void merge(int x,int y)
}void dfs(int x,int fa)
} multiset::iterator it=s[x].lower_bound(a[x]);
if(it==s[x].end()) s[x].insert(a[x]);
else
}int main()
} dfs(1,0);
printf("%d\n",s[1].size());
}
BZOJ4919 大根堆 樹上LIS
題目描述見鏈結 樹上 lis lisli s 問題,使用std multisetst維護當前子樹內所有可能的 lis lisli s 結尾,從前往後 lis lisli s結尾 對應的長度遞增 子樹之間互不影響,只需考慮子樹根節點 u uu 對子樹內的影響,模擬 序列lis lisli s 的做法,...
bzoj 4919 大根堆(set啟發式合併)
傳送門biu 假設是在序列上,就變成了nlogn的dp求最長上公升子串行問題 假設是在樹上,我們只需要在每個節點存下dp陣列,然後用set的啟發式合併將dp陣列合併就可以了 代替splay include define n 200005 using namespace std vector e n ...
題解 BZOJ4919 大根堆
題面 傳送門。老師說今天要考一道線段樹合併,然後。然後這道題我就gg了。當然可以用線段樹合併寫,只是比較複雜 有人賽時想了個貪心,然後被機房巨佬hack了,結果在hack的過程中巨佬想出了正解。貪心思路 對於乙個節點,取右邊的 大一點的 肯定更優。其實很好hack啊,隨便搞一條鏈就可以了 ac思路 ...