题目简述:树版[k取方格数]
众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。今天他得到了一款新游戏《XX
半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状
结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同
时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
“为什么你还没玩就知道每个场景的价值呢?”
“我已经看到结局了。”
Input
第一行两个正整数n,k
第二行n个正整数,表示每个场景的价值
以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)
保证场景1为根节点
n<=200000,1<=场景价值<=2^31-1
Output
输出一个整数表示答案
Sample Input
5 2 4 3 2 1 1 1 2 1 5 2 3 2 4
Sample Output
10
思路: 贪心的去想,就是我们先取出权值最大的一条链,然后逐个更新链上的每个点的子树,更新完之后再取出最大的一条链,那么我们就需要一种快速的取最大值和id的方案,当然线段树,当然要配合dfs序,我们在更新的时候,如果更新到的这个节点已经被更新过了,那么就可以直接跳出了,因为每个节点最多只能被用一次。
思路2: 我们对于每一个节点,我把这个节点的权值给他的若干个孩子中的哪个孩子呢,当然我尽量的想给最大的那个孩子,然后我们可以对于每个一个节点维护一个可并堆,就可以直接把当前节点的权值给权值最大的孩子链,那么一路dfs回退,回退到根节点,堆顶的前k个元素就是答案呗。
代码:
///11111111111111111111111111111111111111111111
#include<bits/stdc++.h>
#define lson (i<<1)
#define rson (i<<1|1)
using namespace std;
typedef long long ll;
const int N =200005;
struct node
{
int l,r;
int mxid;
ll lz;
ll maxx;
}tr[N<<2];
vector<int >ve[N];
int tim;
int L[N];
int R[N];
int dfns[N];
int dfn;
int f[N];
int vis[N];
ll w[N];
ll val[N];
int n;
void dfs(int u,int fa)
{
val[u]=val[fa]+w[u];
f[u]=fa;
dfns[++dfn]=u; L[u]=dfn;
for(int i=0;i<ve[u].size();i++){
int v=ve[u][i];
if(v==fa) continue;
dfs(v,u);
}
R[u]=dfn;
}
void push_up(int i)
{
ll &maxx=tr[i].maxx; int &mxid=tr[i].mxid;
if(tr[lson].maxx>=tr[rson].maxx){
maxx=tr[lson].maxx; mxid=tr[lson].mxid;
}
else{
maxx=tr[rson].maxx; mxid=tr[rson].mxid;
}
}
void push_down(int i)
{
ll &lz=tr[i].lz;
if(lz){
tr[lson].maxx-=lz; tr[lson].lz+=lz;
tr[rson].maxx-=lz; tr[rson].lz+=lz;
lz=0;
}
}
void build(int i,int l,int r)
{
tr[i].l=l; tr[i].r=r; tr[i].lz=0; tr[i].maxx=0; tr[i].mxid=0;
if(l==r){
tr[i].maxx=val[dfns[l]];
tr[i].mxid=dfns[l];
return ;
}
int mid=(l+r)>>1;
build(lson,l,mid);
build(rson,mid+1,r);
push_up(i);
}
void update(int i,int l,int r,ll lz)
{
if(tr[i].l==l&&tr[i].r==r){
tr[i].maxx-=lz;
tr[i].lz+=lz;
return ;
}
push_down(i);
int mid=(tr[i].l+tr[i].r)>>1;
if(r<=mid) update(lson,l,r,lz);
else if(l>mid) update(rson,l,r,lz);
else{
update(lson,l,mid,lz);
update(rson,mid+1,r,lz);
}
push_up(i);
}
int main()
{
int k;
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
int u,v;
for(int i=1;i<n;i++){
scanf("%d %d",&u,&v);
ve[u].push_back(v);
ve[v].push_back(u);
}
dfs(1,0);
build(1,1,n);
ll ans=0;
while(k--)
{
ans+=tr[1].maxx;
int id=tr[1].mxid;
while(1){
if(id==0) break;
if(vis[id]) break;
int l,r;
l=L[id]; r=R[id];
update(1,l,r,w[id]);
vis[id]=1;
id=f[id];
}
}
printf("%lld\n",ans);
return 0;
}
/// 222222222222222222222222222222222
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N =2e5+5;
vector<int >ve[N];
struct merge_dui
{
int l,r;
int dis;
ll val;
}T[N];
int root[N];
int cnode;
ll w[N];
int n;
int Merge(int r1,int r2)
{
if(r1==0||r2==0) return r1+r2;
if(T[r1].val<T[r2].val) swap(r1,r2);
T[r1].r=Merge(T[r1].r,r2);
if(T[T[r1].l].dis<T[T[r1].r].dis) swap(T[r1].l,T[r1].r);
T[r1].dis=T[T[r1].r].dis+1;
return r1;
}
void dfs(int u,int fa)
{
if(ve[u].size()==1&&fa!=-1){
root[u]=++cnode;
T[root[u]].val=w[u];
return ;
}
root[u]=0;
T[root[u]].val=0;
for(int i=0;i<ve[u].size();i++){
int v=ve[u][i];
if(v==fa) continue;
dfs(v,u);
root[u]=Merge(root[u],root[v]);
}
T[root[u]].val+=w[u];
return ;
}
int Pop(int rt)
{
return Merge(T[rt].l,T[rt].r);
}
int main()
{
int k,u,v;
scanf("%d %d",&n,&k);
for(int i=1;i<=n;i++) scanf("%lld",&w[i]);
for(int i=1;i<n;i++){
scanf("%d %d",&u,&v);
ve[u].push_back(v);
ve[v].push_back(u);
}
dfs(1,-1);
ll ans=0;
while(k--)
{
ans+=T[root[1]].val;
root[1]=Pop(root[1]);
}
printf("%lld\n",ans);
return 0;
}