[bzoj3252]攻略_dfs序_线段树_贪心
攻略 bzoj-3252
题目大意:给定一棵n个节点的有根树,点有点权。让你选出至多k个节点,使得他们到根的链的并最大。
注释:$1\le n\le 2\cdot 10^5$,$1\le val_i\le 2^{31}-1$。
想法:这题模拟赛T2,正解可并堆,我用的$dfs$序加线段树。
考虑暴力:显然每次选取当前贡献最大的一定是最优的,一个非常显然的贪心。
我们对每个节点维护一个$dis$表示当前节点选取的贡献。如果我们选取了一个节点$x$那么以$x$为根的子树都会减去$val_x$。
显然一个节点只会被选取一次,所以如果我们每次可以快速找到最大值的位置,我们就可以对以$x$为根的子树进行子树减。
故此我们在线段树上的每个节点都维护一个$son$信息,表示线段树上的最大值是左儿子贡献的还是右儿子贡献的。
对于线段树上的叶子节点再维护一下这个叶子对应原树的哪个节点。
这样的话每次我们从根开始通过那个$son$信息找到最大的贡献节点,然后从当前节点开始向根遍历知道遇到被选取过的节点。每遍历到一个节点都进行一遍子树减即可。
总时间复杂度$O(nlogn)$。
Code:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 200010
#define ls p<<1
#define rs p<<1|1
using namespace std; typedef long long ll;
struct Node
{
ll mx,del; int id,son;
}a[N<<2];
ll dis[N]; int dic[N],cnt,val[N],re[N],f[N],size[N];
int to[N<<1],nxt[N<<1],head[N],tot;
bool vis[N];
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
ll rd() {ll x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
inline void add(int x,int y) {to[++tot]=y; nxt[tot]=head[x]; head[x]=tot;}
inline void pushup(int p)
{
a[p].mx=max(a[ls].mx,a[rs].mx);
a[p].son=(a[ls].mx>=a[rs].mx?1:2);
}
inline void pushdown(int p)
{
if(!a[p].del) return;
a[ls].mx+=a[p].del; a[ls].del+=a[p].del;
a[rs].mx+=a[p].del; a[rs].del+=a[p].del;
a[p].del=0;
}
void build(int l,int r,int p)
{
if(l==r) {a[p].mx=dis[re[l]],a[p].id=re[l]; return;}
int mid=(l+r)>>1;
build(l,mid,ls); build(mid+1,r,rs);
pushup(p);
}
void update(int x,int y,ll val,int l,int r,int p)
{
if(x<=l&&r<=y)
{
a[p].mx+=val; a[p].del+=val;
return;
}
int mid=(l+r)>>1; pushdown(p);
if(x<=mid) update(x,y,val,l,mid,ls);
if(mid<y) update(x,y,val,mid+1,r,rs);
pushup(p);
}
int query_son(int l,int r,int p)
{
if(l==r) return p;
int mid=(l+r)>>1; pushdown(p);
if(a[p].son==1) return query_son(l,mid,ls);
else return query_son(mid+1,r,rs);
}
void dfs(int pos,int fa)
{
dis[pos]=dis[fa]+val[pos];
f[pos]=fa;
dic[pos]=++cnt; re[cnt]=pos;
size[pos]=1;
for(int i=head[pos];i;i=nxt[i]) if(to[i]!=fa)
{
dfs(to[i],pos);
size[pos]+=size[to[i]];
}
}
int main()
{
ll ans=0;
int n=rd(),k=rd();
for(int i=1;i<=n;i++) val[i]=rd();
for(int i=1;i<n;i++)
{
int x=rd(),y=rd(); add(x,y); add(y,x);
}
dfs(1,0);
build(1,n,1);
while(k--)
{
int p=query_son(1,n,1);
ans+=a[p].mx;
int x=a[p].id;
while(x&&!vis[x])
{
update(dic[x],dic[x]+size[x]-1,-val[x],1,n,1); val[x]=0;
vis[x]=true;
x=f[x];
}
}
cout << ans << endl ;
// fclose(stdin); fclose(stdout);
return 0;
}
小结:从暴力入手是一个非常好的选择。
[bzoj3252]攻略_dfs序_线段树_贪心的更多相关文章
- bzoj3252 攻略 dfs序+线段树
题目传送门 题目大意:给出一棵树,1为根节点,每个节点都有权值,每个叶子节点都是一个游戏的结局,选择k个游戏结局,使得权值总和最大,同一个节点不会被重复计算. 思路:这道题最关键的是要想到一个性质,就 ...
- [bzoj3306]树_dfs序_线段树_倍增lca
树 bzoj-3306 题目大意:给定一颗n个节点的树,支持换根.修改点权.查询子树最小值. 注释:$1\le n,q\le 10^5$. 想法: 如果没有换根操作,就是$dfs$序+线段树维护区间最 ...
- [Cometoj#3 D]可爱的菜菜子_线段树_差分_线性基
可爱的菜菜子 题目链接:https://cometoj.com/contest/38/problem/D?problem_id=1543 数据范围:略. 题解: 首先,如果第一个操作是单点修改,我们就 ...
- [LuoguP3064][USACO12DEC]伊斯坦布尔的帮派Gangs of Istanbull(加强版)_线段树_贪心
伊斯坦布尔的帮派Gangs of Istanbull 题目链接:https://www.luogu.org/problem/P3064 数据范围:略. 题解: 这个题其实分为两问,第一问是$YES$. ...
- [bzoj2962]序列操作_线段树_区间卷积
序列操作 bzoj-2962 题目大意:给定一个n个数的正整数序列,m次操作.支持:1.区间加:2.区间取相反数:3.区间求选c个数的乘积和. 注释:$1\le n,m\le 5\cdot 10^4$ ...
- [计蒜客T2238]礼物_线段树_归并排序_概率期望
礼物 题目大意: 数据范围: 题解: 这题有意思啊($md$卡常 直接做怎么做? 随便上个什么东西,维护一下矩阵乘和插入,比如说常数还算小的$KD-Tree$(反正我是没见人过过 我们漏掉了一个条件, ...
- [bzoj5379]Tree_dfs序_线段树_倍增lca
Tree bzoj-5379 题目大意:给定一棵$n$节点的树.支持:换根.把节点$u$和$v$的$lca$的子树加.询问$u$的子树和. 注释:$1\le n,q\le 3\times 10^5$. ...
- 洛谷 P2542 [AHOI2005]航线规划 树链剖分_线段树_时光倒流_离线
Code: #include <map> #include <cstdio> #include <algorithm> #include <cstring&g ...
- BZOJ_3252_攻略_线段树+dfs序
BZOJ_3252_攻略_线段树+dfs序 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏.今天他得到了一款新游戏< ...
随机推荐
- IIS7.0中Process打开cmd程序出现问题
本人在VS中用Process打开cmd程序,并传入参数,转换图片,运行成功! 但是放入IIS7.0中,Process打不开cmd程序,程序直接运行过去,无结果,无报错! 解决方案: 将IIS里面你程序 ...
- C语言基础-运算符
sizeof()运算符 •sizeof可以用来计算一个变量或者一个常量.一种数据类型所占的内存字节数 •sizeof一共有3种形式 1.sizeof( 变量\常量 ) sizeof(10 ...
- GA详解
转:http://blog.csdn.net/u010451580/article/details/51178225 本文是去年课题组周报中的一个专题讲解,详细讲了GA,由于是周报,所以十分详细.很适 ...
- python与shell通过微信企业号发送消息
python与shell通过微信企业号发送信息,脚本来源于网络,做好搬运工,哈哈,相应的参考链接放在末位 shell版本: #!/bin/bash # CropID="xxxx" ...
- inux 软件编译、安装、删除
640?wx_fmt=otherimage.png 本文学习内容 手动安装软件 手动安装下载源码的软件 源码编译3步骤 deb包-包依赖管理 dekg -l 查看所以安装deb的包 apt-get仓库 ...
- SQL GROUP BY 和 ORDER BY 区别
order by 是按表中某字段排列表中数据group by 是按某些字段分类. 例如按 1.按年龄排序表中的记录select * from users order by age 2.按年龄分类表中数 ...
- redis简介以及安装
redis作为开源的高性能的键值对数据库,本身是单线程的,性能虽然没有memcache高,但是也是性能跟memcache相差无几的,memcache是多线程的,但是redis本身功能更加强大,学习一下 ...
- javascript的prototype经典使用场景
prototype的经典使用场景就是为对象增加属性和方法,如给自定义的Man对象增加个姓名属性和语言方法: function man() { this.age = "22&qu ...
- 路径工具类NSPathUtilities
路径工具类NSPathUtilities.h 路径类NSPathUtilities.h包含了 NSString的函数和分类扩展,他允许你操作路径名.应该竟可能的使用这些函数,以便使程序更独立于文件系统 ...
- MRC转ARC
转载请注明出处:http://blog.csdn.net/cywn_d/article/details/18222671 1.删除所有retain,release和autorelease. 2.把原来 ...