bzoj3252 攻略 dfs序+线段树
题目大意:给出一棵树,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
Input
Output
Sample Input
4 3 2 1 1
1 2
1 5
2 3
2 4
Sample Output
bzoj3252 攻略 dfs序+线段树的更多相关文章
- 【BZOJ-3252】攻略 DFS序 + 线段树 + 贪心
3252: 攻略 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 339 Solved: 130[Submit][Status][Discuss] D ...
- 【BZOJ3252】攻略 DFS序+线段树(模拟费用流)
[BZOJ3252]攻略 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛> ...
- Educational Codeforces Round 6 E dfs序+线段树
题意:给出一颗有根树的构造和一开始每个点的颜色 有两种操作 1 : 给定点的子树群体涂色 2 : 求给定点的子树中有多少种颜色 比较容易想到dfs序+线段树去做 dfs序是很久以前看的bilibili ...
- Codeforces 343D Water Tree(DFS序 + 线段树)
题目大概说给一棵树,进行以下3个操作:把某结点为根的子树中各个结点值设为1.把某结点以及其各个祖先值设为0.询问某结点的值. 对于第一个操作就是经典的DFS序+线段树了.而对于第二个操作,考虑再维护一 ...
- BZOJ2434 [Noi2011]阿狸的打字机(AC自动机 + fail树 + DFS序 + 线段树)
题目这么说的: 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿狸研究发现,这个打字机是这样工作的: 输入小 ...
- POJ 3321 DFS序+线段树
单点修改树中某个节点,查询子树的性质.DFS序 子树序列一定在父节点的DFS序列之内,所以可以用线段树维护. 1: /* 2: DFS序 +线段树 3: */ 4: 5: #include < ...
- 【XSY2667】摧毁图状树 贪心 堆 DFS序 线段树
题目大意 给你一棵有根树,有\(n\)个点.还有一个参数\(k\).你每次要删除一条长度为\(k\)(\(k\)个点)的祖先-后代链,问你最少几次删完.现在有\(q\)个询问,每次给你一个\(k\), ...
- F - Change FZU - 2277 (DFS序+线段树)
题目链接: F - Change FZU - 2277 题目大意: 题意: 给定一棵根为1, n个结点的树. 有q个操作,有两种不同的操作 (1) 1 v k x : a[v] += x, a[v ' ...
- BZOJ4551[Tjoi2016&Heoi2016]树——dfs序+线段树/树链剖分+线段树
题目描述 在2016年,佳媛姐姐刚刚学习了树,非常开心.现在他想解决这样一个问题:给定一颗有根树(根为1),有以下 两种操作:1. 标记操作:对某个结点打上标记(在最开始,只有结点1有标记,其他结点均 ...
随机推荐
- c语言实践 打印三角形
效果如下: 我是怎么考虑这个问题的. 首先共有5行,那么我们需要一个循环,让这个循环走5遍. 那么我们有个大概的代码结构 for(int i=0;i<5;i++) { } i的定义域是[0,4] ...
- 二项分布 , 多项分布, 以及与之对应的beta分布和狄利克雷分布
1. 二项分布与beta分布对应 2. 多项分布与狄利克雷分布对应 3. 二项分布是什么?n次bernuli试验服从 二项分布 二项分布是N次重复bernuli试验结果的分布. bernuli实验是什 ...
- ShopNc登录
- Part3_lesson4---协处理器访问指令
1.什么是协处理器? CP15是协处理器, CP15的作用:系统控制协处理器CP15,它提供了额外的寄存器,这些寄存器用于配置和控制cache,MMU,保护系统,时钟模式,和其他的系统项,比如大小端操 ...
- hdu 4279 Number(G++提交)
打表找规律: #include<stdio.h> #include<math.h> #define N 250 bool judge(int i,int j) { ;k< ...
- 在IE11(Win8)中检查up6.2配置
1.按F12,打开调试模式 2.打开调试程序选项卡 说明:在调试程序选项卡中可看到IE加载的脚本信息是否正确.因为IE有缓存,导致脚本有时不是最新的. 3.打开脚本,up6.js ...
- jQuery插件扩展extend的实现原理
相信每位前端的小伙伴对jQuery都不陌生吧,它最大的魅力之一就是有大量的插件,去帮助我们更轻松的实现各种功能. 前几天晚上,闲来无事,就自己动手写了个简单的jQuery插件,功能很简单,只是让选定的 ...
- angular 事件绑定
<button (click)="onClick($event)">点我</button> import { Component, OnInit } fro ...
- web.xml报错:cvc-complex-type.2.4.a: Invalid content was found starting with element 'async-supported'. One of '{"http://java.sun.com/xml/ns/javaee":init-param}' is expected.
在写xml的时候又一次总是报cvc-complex-type.2.4.a: Invalid content was found starting with element 错误,还出现小红叉,在网上找 ...
- ES更改参数max_result_window
今天开发那边说翻页超过10000报错.早上来查阅官网手册,说from/size默认是10000.通过参数index.max_result_window进行控制.那么直接改这个参数即可. 1.先看看默认 ...