bzoj3252 攻略

来源:互联网 发布:淘宝店不刷信誉可以吗 编辑:程序博客网 时间:2024/05/04 23:31

3252: 攻略

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 278  Solved: 99
[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序+线段树




很显然这道题是满足贪心性质的,每次只要选择权值和最大的路径。(原因请读者自己思考...2333)

首先我们考虑取走一个点后对那些点到根节点的权值和有影响。答案显而易见,对该节点子树中的节点有影响。

所以我们可以维护每个点到根节点的权值和sum,每次选择sum值最大的点,并改变它的子树中所有节点的sum值。

那么如何快速地实现这一操作呢?

我们可以用DFS序将一棵子树转化为一个连续的区间,于是问题就转化为区间修改、单点查询,显然用线段树实现。




#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<cstdlib>#define F(i,j,n) for(int i=j;i<=n;i++)#define D(i,j,n) for(int i=j;i>=n;i--)#define ll long long#define maxn 200005#define inf 1000000000000000llusing namespace std;int n,m,cnt,tot,x,y;int head[maxn],fa[maxn],l[maxn],r[maxn],f[maxn];ll ans,a[maxn],sum[maxn];bool vst[maxn];struct edge_type{int next,to;}e[maxn];struct seg_type{int l,r;ll mx,pos,tag;}t[maxn*4];inline int read(){int x=0,f=1;char ch=getchar();while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}inline void add_edge(int x,int y){e[++cnt]=(edge_type){head[x],y};head[x]=cnt;fa[y]=x;}inline void dfs(int x){f[l[x]=++tot]=x;for(int i=head[x];i;i=e[i].next){int y=e[i].to;sum[y]=sum[x]+a[y];dfs(y);}r[x]=tot;}inline void pushup(int k){int lc=k<<1,rc=k<<1|1;t[k].mx=0;if (t[lc].mx>t[k].mx){t[k].mx=t[lc].mx;t[k].pos=t[lc].pos;}if (t[rc].mx>t[k].mx){t[k].mx=t[rc].mx;t[k].pos=t[rc].pos;}}inline void update(int k,ll x){t[k].mx-=x;t[k].tag+=x;}inline void pushdown(int k){if (!t[k].tag) return;update(k<<1,t[k].tag);update(k<<1|1,t[k].tag);t[k].tag=0;}inline void build(int k,int l,int r){t[k].l=l;t[k].r=r;t[k].tag=0;if (l==r){t[k].mx=sum[f[l]];t[k].pos=l;return;}int mid=(l+r)>>1;build(k<<1,l,mid);build(k<<1|1,mid+1,r);pushup(k);}inline void add(int k,int x,int y,ll z){int l=t[k].l,r=t[k].r,mid=(l+r)>>1;if (l==x&&r==y){update(k,z);return;}pushdown(k);if (y<=mid) add(k<<1,x,y,z);else if (x>mid) add(k<<1|1,x,y,z);else{add(k<<1,x,mid,z);add(k<<1|1,mid+1,y,z);}pushup(k);}int main(){n=read();m=read();F(i,1,n) a[i]=read();F(i,1,n-1){x=read();y=read();add_edge(x,y);}sum[1]=a[1];dfs(1);build(1,1,n);while (m--){ans+=t[1].mx;for(int i=f[t[1].pos];!vst[i]&&i;i=fa[i]){vst[i]=true;add(1,l[i],l[i],inf);if (l[i]<r[i]) add(1,l[i]+1,r[i],a[i]);}}printf("%lld\n",ans);return 0;}


0 0
原创粉丝点击