BZOJ 3252: 攻略 贪心 树链剖分

来源:互联网 发布:阿里云tts 编辑:程序博客网 时间:2024/06/07 22:50

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序+线段树


有很多写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 24 3 2 1 11 21 52 32 410*/