3252: 攻略

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

Solution

比较好想的一道题

首先,K次攻略,使总价值最大,显然每次攻略当前最大即可

我们定义一个节点的Val为根到这个节点的∑val

那么我们用线段树维护一下这个东西,每次取最大。

考虑统计一次答案之后,这个点的价值就不存在了,那么我们只需要把这个点到根的路径上的所有点的val在它的子树中减去即可

每个点只减一次就可以了....

所以时间复杂度还是$O(nlogn)$的

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
int read()
{
int x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define MAXN 200010
#define LL long long
int N,K;
bool visit[MAXN];
LL sumV[MAXN],val[MAXN];
struct EdgeNode{int next,to;}edge[MAXN<<];
int head[MAXN],cnt=,fa[MAXN];
void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
void InsertEdge(int u,int v) {fa[v]=u; AddEdge(u,v); AddEdge(v,u);}
int pl[MAXN],pr[MAXN],dfn,pre[MAXN];
void DFS(int now,int last)
{
pl[now]=++dfn; pre[dfn]=now;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=last)
sumV[edge[i].to]=sumV[now]+val[edge[i].to],DFS(edge[i].to,now);
pr[now]=dfn;
}
struct SegmentTreeNode{int l,r,maxp; LL maxx,tag;}tree[MAXN<<];
int Maxp(SegmentTreeNode ls,SegmentTreeNode rs) {return ls.maxx>rs.maxx? ls.maxp:rs.maxp;}
void Update(int now)
{
tree[now].maxx=max(tree[now<<].maxx,tree[now<<|].maxx);
tree[now].maxp=Maxp(tree[now<<],tree[now<<|]);
}
void BuildTree(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r;
if (l==r) {tree[now].maxx=sumV[pre[l]]; tree[now].maxp=l; return;}
int mid=(l+r)>>;
BuildTree(now<<,l,mid); BuildTree(now<<|,mid+,r);
Update(now);
}
void PushDown(int now)
{
if (tree[now].l==tree[now].r || !tree[now].tag) return;
LL tag=tree[now].tag; tree[now].tag=;
tree[now<<].maxx+=tag; tree[now<<|].maxx+=tag;
tree[now<<].tag+=tag; tree[now<<|].tag+=tag;
}
void Change(int now,int L,int R,int val)
{
PushDown(now);
int l=tree[now].l,r=tree[now].r;
if (L<=l && R>=r) {tree[now].maxx+=val; tree[now].tag+=val; return;}
int mid=(l+r)>>;
if (L<=mid) Change(now<<,L,R,val);
if (R>mid) Change(now<<|,L,R,val);
Update(now);
}
int main()
{
N=read(); K=read();
for (int i=; i<=N; i++) val[i]=read();
for (int x,y,i=; i<=N-; i++) x=read(),y=read(),InsertEdge(x,y);
sumV[]=val[]; DFS(,);
// for (int i=1; i<=N; i++)
// printf("ID=%d [%d , %d] %d %d\n",pre[i],pl[pre[i]],pr[pre[i]],val[pre[i]],sumV[pre[i]]);
LL ans=;
BuildTree(,,N);
for (int i=; i<=K; i++)
{
// printf("NOW=%d : %d , %d\n",i,tree[1].maxx,tree[1].maxp);
if (tree[].maxx>) ans+=tree[].maxx; else break;
for (int x=pre[tree[].maxp]; !visit[x]&&x; x=fa[x])
visit[x]=,Change(,pl[x],pr[x],-val[x]);
}
printf("%lld\n",ans);
return ;
}

第一次明白攻略组的意思....大概是看刀剑的时候吧/....

【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心的更多相关文章

  1. bzoj3252 攻略 dfs序+线段树

    题目传送门 题目大意:给出一棵树,1为根节点,每个节点都有权值,每个叶子节点都是一个游戏的结局,选择k个游戏结局,使得权值总和最大,同一个节点不会被重复计算. 思路:这道题最关键的是要想到一个性质,就 ...

  2. 【BZOJ3252】攻略 DFS序+线段树(模拟费用流)

    [BZOJ3252]攻略 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛> ...

  3. bzoj 3252 攻略 长链剖分思想+贪心

    攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 889  Solved: 423[Submit][Status][Discuss] Descrip ...

  4. bzoj 3252: 攻略 -- 长链剖分+贪心

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MB Description 题目简述:树版[k取方格数]   众所周知,桂木桂马是攻略之神,开启攻略之神 ...

  5. BZOJ.3252.攻略(贪心 长链剖分/线段树)

    题目链接 贪心,每次选价值最大的一条到根的链.比较显然(不选白不选). 考虑如何维护这个过程.一个点的价值选了就没有了,而它只会影响它子树里的点,可以用DFS序+线段树修改.而求最大值也可以用线段树. ...

  6. BZOJ 3252题解(贪心+dfs序+线段树)

    题面 传送门 分析 此题做法很多,树形DP,DFS序+线段树,树链剖分都可以做 这里给出DFS序+线段树的代码 我们用线段树维护到根节点路径上节点权值之和的最大值,以及取到最大值的节点编号x 每次从根 ...

  7. DFS序+线段树(bzoj 4034)

    题目链接 题目就不多说了. 本题目,可以用dfs序+线段树做:题目给定了一棵树,树上节点告诉了权值.我们可以先将这棵树进行dfs将一棵树变成线性结构:如图 变成这样后,然后就可以用线段树. 操作1:也 ...

  8. 【贪心】 BZOJ 3252:攻略

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 261  Solved: 90[Submit][Status][Discuss] De ...

  9. bzoj 3252: 攻略

    3252: 攻略 Description 题目简述:树版[k取方格数]   众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛>, ...

随机推荐

  1. Java集合系列:-----------03ArrayList源码分析

    上一章,我们学习了Collection的架构.这一章开始,我们对Collection的具体实现类进行讲解:首先,讲解List,而List中ArrayList又最为常用.因此,本章我们讲解ArrayLi ...

  2. 040医疗项目-模块四:采购单模块—采购单创建好之后跳转到采购单修改页面(editcgd.action)

    我们上一篇文章写到了要从editcgd.action为入口讲.我们要做的事根据edicgd.acion进入到Action层的一个函数,在这个函数里面要做的就是从数据库中把采购单表里面的数据都查出来显示 ...

  3. [转]源代码的管理和发布:以SVN为例

    FROM : http://ju.outofmemory.cn/entry/47277 前几天在微博吐槽了SVN的几个不爽的地方:.svn文件满天飞.分支管理的麻烦.不爽一般来说都是有过对比后才有如此 ...

  4. noi题库(noi.openjudge.cn) 1.8编程基础之多维数组T01——T10

    T01 矩阵交换行 描述 给定一个5*5的矩阵(数学上,一个r×c的矩阵是一个由r行c列元素排列成的矩形阵列),将第n行和第m行交换,输出交换后的结果. 输入 输入共6行,前5行为矩阵的每一行元素,元 ...

  5. Method not found: '!!0[] System.Array.Empty()'.

    错误原因:程序里面没有可调用的方法(程序使用的是 .NET Framework 4.6,但是你自己的系统里面使用的不是 4.6版本) 解决方法:1.安装window sp1  ,下载地址是:https ...

  6. &12-2 查找二叉搜索树

    #1,定理 在一棵高度为h的二叉搜索树上,动态集合上的操作SEARCH.MINIMUM.MAXIMUM.SUCCESSOR和PREDECESSOR可以在O(h)时间内完成. #2,伪代码 分别是搜索, ...

  7. java:如何用代码控制H2 Database启动

    1.纯手动start/stop package com.cnblogs.yjmyzz.h2; import java.sql.Connection; import java.sql.DriverMan ...

  8. MvvmLight ToolKit 教程

    MvvmLightToolKit MvvmLightToolKit的源代码是托管在CodePlex上的,我们 可以从这里获取最新版本的源代码,不仅源码,版本发布的日志,更改了哪些,修复了哪些,以及一些 ...

  9. PRML读书会第十一章 Sampling Methods(MCMC, Markov Chain Monte Carlo,细致平稳条件,Metropolis-Hastings,Gibbs Sampling,Slice Sampling,Hamiltonian MCMC)

    主讲人 网络上的尼采 (新浪微博: @Nietzsche_复杂网络机器学习) 网络上的尼采(813394698) 9:05:00  今天的主要内容:Markov Chain Monte Carlo,M ...

  10. Theano3.3-练习之逻辑回归

    是官网上theano的逻辑回归的练习(http://deeplearning.net/tutorial/logreg.html#logreg)的讲解. Classifying MNIST digits ...