题目传送门

  题目大意:给出一棵树,1为根节点,每个节点都有权值,每个叶子节点都是一个游戏的结局,选择k个游戏结局,使得权值总和最大,同一个节点不会被重复计算。

  思路:这道题最关键的是要想到一个性质,就是不管怎么选,当前子树中,叶子节点最重的那一条链肯定要被选择。(可以反证,如果不选这条链,一定不是最优的),那么贪心的想一下,选取这条链之后,把这条链上的所有节点权值变成0,得到的新的树,重复以上过程k次,就得到了我们要的答案。

  要怎么把链节点的权值变成0呢?我们建立线段树的时候,把以每个节点当成末尾节点的链当成一个元素,用这个节点的dfs序当成线段树的序号,做一个可以区间修改,查询最大值并返回下标的线段树,这样每次查询(1,n)区间最大值,就是当前最重的链,得到链后,要把这条链上每一个节点都赋值为0,并且更新其他相关链的信息。我们发现,把一个节点赋值为0,其实就是把这个节点的子树都减去此节点权值,那么就用dfs序进行区间减处理,并且把每个节点是否被删去都标记一下。如果这条链往上走的节点已经被清空了,就不需要再往上走了。这样我们会发现,每个节点最多被删除一次,每一次修改的时间复杂度是logn,所以总复杂度是nlogn,和 k 几乎无关。注意dfs序和原下标的对应。

上代码(bzoj iostream头文件居然ce了。。)

  

#include<cstdio>
#include<cstring>
#include<stdlib.h>
#include<cstdio>
#include<algorithm>
//#include<iostream>
#include<map>
#include<queue>
#include<vector>
#define CLR(a,b) memset(a,b,sizeof(a))
#define lson l , mid , x << 1
#define rson mid + 1 , r , x << 1 | 1
#define PI acos(-1)
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=;
struct edge{
int to,Next;
}e[*maxn];
int n,m;
int tot,head[maxn],u,v,L[maxn],R[maxn],time,dfn[maxn],fa[maxn],ref[maxn];
ll val[maxn],dis[maxn];
bool vis[maxn];
inline void init(){
CLR(head,-),tot=,time=;
CLR(val,);
dis[]=;
CLR(vis,);
}
ll mx[maxn << ] , tag[maxn << ],mp[ maxn << ]; inline void pushup(int x)
{
int l = x << , r = x << | ;
if(mx[l] > mx[r]) mx[x] = mx[l] , mp[x] = mp[l];
else mx[x] = mx[r] , mp[x] = mp[r];
}
inline void pushdown(int x)
{
if(tag[x])
{
int l = x << , r = x << | ;
mx[l] -= tag[x] , mx[r] -= tag[x];
tag[l] += tag[x] , tag[r] += tag[x];
tag[x] = ;
}
}
inline void build(int l , int r , int x)
{
if(l == r)
{
mx[x] = dis[l] , mp[x] = l;
return;
}
int mid = (l + r) >> ;
build(lson) , build(rson);
pushup(x);
}
inline void update(int b , int e , ll a , int l , int r , int x)
{
if(b <= l && r <= e)
{
mx[x] -= a , tag[x] += a;
return;
}
pushdown(x);
int mid = (l + r) >> ;
if(b <= mid) update(b , e , a , lson);
if(e > mid) update(b , e , a , rson);
pushup(x);
} inline void addv(int u,int v){
e[++tot]={v,head[u]};
head[u]=tot;
} inline void dfs(int u,int pre){
fa[u]=pre;
dfn[++time]=u;
ref[u]=time;
L[u]=time;
dis[time]=val[u]+dis[ref[pre]];
for(int i=head[u];i!=-;i=e[i].Next)
{
int v=e[i].to;
if(v==pre)continue;
dfs(v,u);
}
R[u]=time;
}
int main(){
int k;
while(scanf("%d%d",&n,&k)!=EOF)
{
init();
for(int i=;i<=n;i++)
{
scanf("%lld",&val[i]);
}
for(int i=;i<n;i++)
{
scanf("%d%d",&u,&v);
addv(u,v);
addv(v,u);
} dfs(,);
build(,n,);
ll ans=;
int x; while(k--)
{
ans+=mx[],x=mp[];
while(x && !vis[x])
{
update(L[dfn[x]],R[dfn[x]],val[dfn[x]],,n,);
vis[x]=;
x=ref[fa[dfn[x]]]; }
}
printf("%lld\n",ans); }
}

Description

题目简述:树版[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

bzoj3252 攻略 dfs序+线段树的更多相关文章

  1. 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心

    3252: 攻略 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 339  Solved: 130[Submit][Status][Discuss] D ...

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

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

  3. Educational Codeforces Round 6 E dfs序+线段树

    题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...

  4. Codeforces 343D Water Tree(DFS序 + 线段树)

    题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...

  5. BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)

    题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...

  6. POJ 3321 DFS序+线段树

    单点修改树中某个节点,查询子树的性质.DFS序 子树序列一定在父节点的DFS序列之内,所以可以用线段树维护. 1: /* 2: DFS序 +线段树 3: */ 4:   5: #include < ...

  7. 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树

    题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...

  8. F - Change FZU - 2277 (DFS序+线段树)

    题目链接: F - Change FZU - 2277 题目大意: 题意: 给定一棵根为1, n个结点的树. 有q个操作,有两种不同的操作 (1) 1 v k x : a[v] += x, a[v ' ...

  9. BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树

    题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...

随机推荐

  1. 2-python代码坑点

    #切片: # L = ['aaa', 'bbb', 'ccc', 'ddd'] # print(L[1 : 3]) #取[1, 3):下标 # L = list(range(100)) # print ...

  2. CentOS双网卡双IP设置

    CentOS双网卡双IP设置 系统环境:CentOS Linux 网络环境: 两个IP地址,192.168.0.10和10.10.30.2,掩码是255.255.255.0,这两个子网的网关地址分别是 ...

  3. CentOS7下源码包方式安装rabbitmq

    1.先安装erlang http://www.cnblogs.com/justphp/p/6093880.html 2.下载rabbitmq rpm包: wget http://www.rabbitm ...

  4. HDU 3362 Fix (状压DP)

    题意:题目给出n(n <= 18)个点的二维坐标,并说明某些点是被固定了的,其余则没固定,要求添加一些边,使得还没被固定的点变成固定的, 要求总长度最短. 析:由于这个 n 最大才是18,比较小 ...

  5. Graphics 小记

    1.切图 drowg.DrawImage(productImg1, new System.Drawing.Rectangle(30, 30, 300, 300), new System.Drawing ...

  6. 从头开始学eShopOnContainers——Visual Studio 2017环境配置

    一.安装和配置Docker环境 1.安装Docker CE for Windows 从官方网站下载并安装,https://docs.docker.com/docker-for-windows/inst ...

  7. [译] 关于 SPA,你需要掌握的 4 层 (1)

    此文已由作者张威授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 我们从头来构建一个 React 的应用程序,探究领域.存储.应用服务和视图这四层 每个成功的项目都需要一个清晰 ...

  8. Xcode打包提交至itunes connect后,提交审核成功,随后出现二进制文件无效

    1.问题描述 Xcode打包提交至itunes connect后,提交审核成功,应用处于待审核状态,过了大概半个小时状态更改为二进制文件无效 2.原因分析 2.1 登陆在苹果中预留的邮箱 ---- 邮 ...

  9. Linux环境下jdk、tomcat、redis安装及配置

    环境说明: linux : centOS jdk : 1.8 tomcat : 8.5 redis : 4.0 jdk安装配置 1.下载jdk(这里下载的是jdk-8u181-linux-x64.ta ...

  10. <id name="ID"> <generator class="assigned" /> </id>

    <generator>表示一个主键的生成机制.即具体通过何种方式来生成.生成方式包括:increment:生成long, short或者int类型的主键,不能在cluster环境下使用.适 ...