BZOJ 3252: 攻略 贪心 树链剖分

版权声明:想转就转吧,注明出处就行 括弧笑 https://blog.csdn.net/BlackJack_/article/details/78217341

3252: 攻略

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 541  Solved: 233
[Submit][Status][Discuss]

Description

题目简述:树版[k取方格数]
 
众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。
今天他得到了一款新游戏《XX半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
“为什么你还没玩就知道每个场景的价值呢?”
“我已经看到结局了。”

Input

第一行两个正整数n,k
第二行n个正整数,表示每个场景的价值
以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)
保证场景1为根节点

Output

输出一个整数表示答案

Sample Input

5 2
4 3 2 1 1
1 2
1 5
2 3
2 4

Sample Output

10

HINT

对于100%的数据,n<=200000,1<=场景价值<=2^31-1

Source


有很多写dfs+线段树的 就是上面的hint....

先说这个做法

很明显 每次贪心选择权值最大的链是最优的策略

然后每个点删除后会影响它的子树

所以就是想怎么维护

之后BJ卡了一下 后来又想到每个点只能被访问一次

然后就发现自己十分low

只需要暴力从叶子向上跳就好了,到被访问过的点就停止

那线段树或树状数组维护一下权值就行了


但是这个题还是有其他的想法的

既然已经解决了子树向上跳的问题,又知道每次会选择到根路径上权值最大的叶子

所以不妨令子节点中向下可延伸权值和最大的点为重儿子,这样剖成的链就是每次选的链了

仍然贪心选就可以了


方法二的代码

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

typedef long long ll;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=200100;

int last[N],ecnt;
struct EDGE{int to,nt;}e[N];
inline void add(int u,int v)
{e[++ecnt]=(EDGE){v,last[u]};last[u]=ecnt;}

int son[N],V[N];

ll mx[N];

void dfs1(int u)
{
	for(int i=last[u];i;i=e[i].nt)
	{
		dfs1(e[i].to);
		if(mx[e[i].to]>mx[u])son[u]=e[i].to,mx[u]=mx[e[i].to];
	}
	mx[u]+=V[u];
}

ll sum[N];

priority_queue<ll>q;

void dfs2(int u)
{
	sum[son[u]]+=sum[u]+V[u];
	if(son[u])dfs2(son[u]);else q.push(sum[u]+V[u]);
	for(int i=last[u];i;i=e[i].nt)
	{
		if(e[i].to==son[u])continue;
		dfs2(e[i].to);
	}
	sum[u]+=V[u];
}

int main()
{
	int n=read(),K=read();ll ans=0;
	register int i,u,v;
	for(i=1;i<=n;++i)V[i]=read();
	for(i=1;i<n;++i){u=read();v=read();add(u,v);}
	dfs1(1);dfs2(1);
	while(!q.empty()&&K--){ans+=q.top();q.pop();}
	cout<<ans<<endl;
	return 0;
}
/*
5 2
4 3 2 1 1
1 2
1 5
2 3
2 4

10
*/
展开阅读全文

没有更多推荐了,返回首页