題目簡述:樹版[k取方格數]
眾所周知,桂木桂馬是攻略之神,開啟攻略之神模式後,他可以同時攻略k部遊戲。今天他得到了一款新遊戲《xx
半島》,這款遊戲有n個場景(scene),某些場景可以通過不同的選擇支到達其他場景。所有場景和選擇支構成樹狀
結構:開始遊戲時在根節點(共通線),葉子節點為結局。每個場景有乙個價值,現在桂馬開啟攻略之神模式,同
時攻略k次該遊戲,問他觀賞到的場景的價值和最大是多少(同一場景**多次是不能重複得到價值的)
「為什麼你還沒玩就知道每個場景的價值呢?」
「我已經看到結局了。」
第一行兩個正整數n,k
第二行n個正整數,表示每個場景的價值
以下n-1行,每行2個整數a,b,表示a場景有個選擇支通向b場景(即a是b的父親)
保證場景1為根節點
n<=200000,1<=場景價值<=2^31-1
輸出乙個整數表示答案
5 24 3 2 1 1
1 21 5
2 32 4
考慮貪心,我們需要找滿足以下條件的 \(k\) 條路徑:
路徑與路徑之間沒有重疊(以不重複計算貢獻);每條路徑的終點一定是葉子;每條路徑要可以直接或間接地到達根(即通過其它路徑)
然後答案要最大,那麼就是要找權值和最大的 \(k\) 條路徑
會發現,這些東西極其地類似於長鏈剖分。我們如果按照權值進行長鏈剖分,可以最優地將樹分割成滿足條件的乙個個路徑,取最大的 \(k\) 個即可
大概證明一下,首先長鏈剖分,每條鏈都是到達葉子節點的,並且肯定不會重複;然後因為是按照權值來剖分的,所以如果最終我們選了乙個起點不是根的鏈,那麼它的的起點的父親所在的鏈一定被選了,因為它們是重鏈和輕鏈的關係
#include#define ui unsigned int
#define ll long long
#define db double
#define ld long double
#define ull unsigned long long
#define rep(a,b,c) for(register int a=b,a##end=c;a<=a##end;++a)
#define dep(a,b,c) for(register int a=b,a##end=c;a>=a##end;--a)
const int maxn=200000+10;
int n,k,e,beg[maxn],nex[maxn],to[maxn],val[maxn],top[maxn],hson[maxn];
ll sum[maxn],mx[maxn],ans;
std::priority_queueq;
templateinline void read(t &x)
templateinline void write(t x,char ch='\0')
templateinline void chkmin(t &x,t y)
templateinline t min(t x,t y)
inline void insert(int x,int y)
inline void dfs1(int x,int f)
mx[x]+=val[x];
}inline void dfs2(int x,int tp)
inline void dfs(int x)
int main()
dfs1(1,0);dfs2(1,1);dfs(1);
while(!q.empty()&&k--)ans+=q.top(),q.pop();
write(ans,'\n');
return 0;
}
BZOJ 3252 攻略 思路題
傳送門 比較好想的一道思路題,結果有個地方沒開 long long wa 了三次。其實就是模仿一下樹鏈剖分,重新定義重兒子,乙個點的重兒子為所有兒子中到葉節點權值最大的點,然後就和樹鏈剖分一樣 dfs 一遍,把那些鏈的頂端的 sum 值放到乙個陣列排個序。include include includ...
BZOJ3252 攻略 可並堆
網上有很多人說用dfs序 線段樹做.其實stl的堆可以.可並堆可以.很多奇奇怪怪的東西都能做.可並堆比較好想.也比較好寫.分析 首先,這是乙個網路流做不了的題.資料太大.其次.我們可以這樣考慮一下,這個點的子樹中,將這個點的權值僅更新給最大的那個就能滿足 之後,在每乙個葉子節點上,建立乙個大根堆,d...
BZOJ 3252攻略 dfs序 線段樹
bzoj 3252 攻略 dfs序 線段樹 題目大意 給定一棵以1為根的n個點的樹,樹有點權且點權為正整數,可以選擇k條以根作為起點的路徑,每條路徑的價值即這條路徑上所有點的點權之和。但是選擇一條路徑之後,這條路徑上的所有點的點權會變成0。也就是說,這k條路徑中被重複選擇的點,其點權只能被計算一次 ...