题目描述
众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。
今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
“为什么你还没玩就知道每个场景的价值呢?”
“我已经看到结局了。”
贪心
对每个点处理从它往下取的最大值以及最优情况下往哪个儿子里去。
然后全部扔进数据结构里。
取k次,每次取出最大的,然后在数据结构中删除其往下路径上的点。
易证。
#include<cstdio>
#include<algorithm>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxn=200000+10;
struct dong{
int x;
ll data;
friend bool operator <(dong a,dong b){
return a.data>b.data||a.data==b.data&&a.x>b.x;
}
};
multiset<dong> s;
int h[maxn],go[maxn*2],next[maxn*2],g[maxn];
ll f[maxn],a[maxn];
int i,j,k,l,t,n,m,tot;
ll ans;
dong zlt;
ll read(){
ll x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x;
}
void add(int x,int y){
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
void dfs(int x,int y){
int t=h[x],j=0;
while (t){
if (go[t]!=y){
dfs(go[t],x);
if (!j||f[go[t]]>f[j]) j=go[t];
}
t=next[t];
}
g[x]=j;
f[x]=f[j]+a[x];
}
int main(){
//freopen("galgame5.in","r",stdin);
n=read();m=read();
fo(i,1,n) a[i]=read();
fo(i,1,n-1){
j=read();k=read();
add(j,k);add(k,j);
}
dfs(1,0);
fo(i,1,n){
zlt.x=i;
zlt.data=f[i];
s.insert(zlt);
}
while (m--){
if (s.empty()) break;
zlt=*s.begin();
ans+=zlt.data;
j=zlt.x;
while (j){
zlt.x=j;
zlt.data=f[j];
s.erase(zlt);
j=g[j];
}
}
printf("%lld\n",ans);
}