bzoj3252 攻略
题目简述:树版[k取方格数]
众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。
今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
“为什么你还没玩就知道每个场景的价值呢?”
“我已经看到结局了。”
Input
第一行两个正整数n,k
第二行n个正整数,表示每个场景的价值
以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)
保证场景1为根节点 对于100%的数据,n<=200000,1<=场景价值<=2^31-1
Output
输出一个整数表示答案
Sample Input
5 2
4 3 2 1 1
1 2
1 5
2 3
2 4
Sol:找出每个点的最长链放入堆中(注意权值是在点上面的),每次找出最长链,并从堆中删除
#include <bits/stdc++.h>
#define debug(a) cout<<#a<<"="<<a<<"\n";
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int N=1e6+7;
struct node {
long long p,son;
} q[N];
long long now[N],s[N],an[N],f[N],son[N],t=0,cnt,ans,n,m,k;
void put(int a,int b) {
q[++t].p=now[a];
now[a]=t;
q[t].son=b;
}
void dfs(int x,int fa) {
for(int i=now[x]; i; i=q[i].p) {
int j=q[i].son;
if(j==fa) continue;
dfs(j,x);
if(f[j]>f[son[x]]) {
son[x]=j;
}
}
f[x]=f[son[x]]+s[x];
for(int i=now[x]; i; i=q[i].p) {
int j=q[i].son;
if(j==fa) continue;
if(j!=son[x])
an[++cnt]=f[j];
}
}
bool cmp(long long a,long long b) {
return a>b;
}
int main()
{
cin>>n>>m;
rep(i,1,n)
cin>>s[i];
rep(i,1,n-1)
{
int a,b,c;
cin>>a>>b;
put(a,b);
put(b,a);
}
dfs(1,0);
an[++cnt]=f[1];
sort(an+1,an+1+cnt,cmp);
rep(i,1,m)
ans+=an[i];
cout<<ans;
return 0;
}
#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 200005;
struct edges
{
int next, to;
edges() {}
edges(int _n, int _t) : next(_n), to(_t) {}
} e[N];
struct data
{
ll first;
int w;
data() {}
data(ll _f, int _w) : first(_f), w(_w) {}
inline bool operator < (const data &b) const
{
return first < b.first;
}
};
int n, k;
int first[N], tot;
int v[N];
bool vis[N];
ll mx[N], ans;
priority_queue <data> h;
inline int read()
{
int x = 0, sgn = 1;
char ch = getchar();
while (ch < '0' || '9' < ch)
{
if (ch == '-') sgn = -1;
ch = getchar();
}
while ('0' <= ch && ch <= '9')
{
x = x * 10 + ch - '0';
ch = getchar();
}
return sgn * x;
}
inline void add_edge(int x, int y)
{
e[++tot] = edges(first[x], y);
first[x] = tot;
}
void dfs(int p)
{
int x, y;
for (x = first[p]; x; x = e[x].next)
dfs(y = e[x].to), mx[p] = max(mx[p], mx[y]);
mx[p] += v[p];
h.push(data(mx[p], p));
//找出每个点的最长链,放到堆中
}
void del(int p)
{
int x, y;
vis[p] = 1;//将其打上删除标记,在堆中并没有删除之
for (x = first[p]; x; x = e[x].next)
if (mx[y = e[x].to] == mx[p] - v[p])
{
del(y);
break;
}
}
int main()
{
int i, p, x, y;
n = read(), k = read();
for (i = 1; i <= n; ++i) v[i] = read();
for (i = 1; i < n; ++i)
{
x = read(), y = read();
add_edge(x, y);
}
dfs(1);
for (; k && !h.empty(); --k)
{
while (vis[h.top().w] && !h.empty())
//如果这个点删除过了,并且堆并不为空时
h.pop();
if (h.empty())
break;
ans += mx[p = h.top().w];
del(p);
}
printf("%lld\n", ans);
return 0;
}

浙公网安备 33010602011771号