BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶
是不是每做道线段树进阶都要写个题解。。根本不会写
Description
给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点。每个点有一个权值v_i。 你需要将这棵树转化成一个大根堆。确切地说,你需要选择尽可能多的节点,满足大根堆的性质:对于任意两个点i,j,如果i在树上是j的祖先,那么v_i>v_j。 请计算可选的最多的点数,注意这些点不必形成这棵树的一个连通子树。
Solution
看起来很像一道DP,实际上也确实要用到DP的思想。
设编号为i的点的子树中最大权值为j的最优方案为fi,j,i的权值为vi
在线段树中维护f,进行标记永久化,不需要进行pushup,在求和时累加路径上的变化量即可。
那么我们就能在对树DFS的过程中进行对f的更新。在每次搜到叶节点后开线段树,回溯时进行线段树合并,并进行对f的维护。
对fi的转移,有取i点和不取i点两种情况。不取i时f最小值为子树中最大权值为v[i]的方案总和,取i时为子树中最大权值为v[i]-1的方案总和数+1。
若不取i的最小值大于取i最大值,则直接return
反之则利用f与v的单调正相关的关系进行二分,找到最优决策点并在线段树中更新即可。
具体看代码
Code:

1 #include<bits/stdc++.h>
2 #define debug cout<<"wrong"<<endl
3 using namespace std;
4 const int NN=2e5+10;
5 int rt[NN],to[NN],nex[NN],head[NN],v[NN],num,ext,n;
6 inline int read(){
7 int x=0,f=1;
8 char ch=getchar();
9 while(ch<'0'||ch>'9'){
10 if(ch=='-') f=-1;
11 ch=getchar();
12 }
13 while(ch<='9'&&ch>='0'){
14 x=(x<<1)+(x<<3)+(ch^48);
15 ch=getchar();
16 }
17 return x*f;
18 }
19 inline void add(int a,int b){
20 to[++num]=b; nex[num]=head[a]; head[a]=num;
21 }
22 void write(int x){
23 if(x<0) putchar('-'), x=-x;
24 if(x>9) write(x/10);
25 putchar(x%10+'0');
26 }
27 void init(){
28 n=read();
29 for(register int i=1;i<=n;i++){
30 v[i]=read();
31 add(read(),i);
32 }
33 int d[NN];
34 for(register int i=1;i<=num;i++) d[i]=v[i];
35 sort(d+1,d+1+num);
36 ext=unique(d+1,d+1+num)-d-1;
37 for(register int i=1;i<=num;i++) v[i]=lower_bound(d+1,d+ext+1,v[i])-d;
38 }
39 struct node{
40 int seg,ls[NN*40],rs[NN*40],num[NN*40];
41 void insert(int &x,int l,int r,int opl,int opr,int val){
42 if(!x) x=++seg;
43 if(opl<=l&&opr>=r){ num[x]+=val; return; }
44 int mid=(l+r)>>1;
45 if(opl<=mid) insert(ls[x],l,mid,opl,opr,val);
46 if(opr>mid) insert(rs[x],mid+1,r,opl,opr,val);
47 }
48 void marge(int &x,int y,int l,int r){
49 if(!x||!y){ x=x+y; return; }
50 num[x]+=num[y];
51 int mid=(l+r)>>1;
52 marge(ls[x],ls[y],l,mid);
53 marge(rs[x],rs[y],mid+1,r);
54 }
55 int query(int x,int l,int r,int pos){
56 if(!x) return 0;
57 int mid=(l+r)>>1,p=num[x];
58 if(pos<=mid) return query(ls[x],l,mid,pos)+p;
59 else return query(rs[x],mid+1,r,pos)+p;
60 }
61 }segt;
62 void dfs(int x){
63 for(register int i=head[x];i;i=nex[i]){
64 dfs(to[i]);
65 segt.marge(rt[x],rt[to[i]],1,ext);
66 }
67 int ans1=segt.query(rt[x],1,ext,v[x]-1)+1;
68 int ans2=segt.query(rt[x],1,ext,v[x]);
69 if(ans1<=ans2) return;
70 int l=v[x],r=ext,mid,pos=v[x];
71 while(l<=r){
72 mid=(l+r)>>1;
73 if(segt.query(rt[x],1,ext,mid)<ans1) l=mid+1, pos=mid;
74 else r=mid-1;
75 }
76 segt.insert(rt[x],1,ext,v[x],pos,1);
77 }
78 int main(){
79 init();
80 dfs(1);
81 write(segt.query(rt[1],1,ext,ext));
82 putchar('\n');
83 return 0;
84 }
Code
BZOJ4919[Lydsy1706月赛]大根堆-------------线段树进阶的更多相关文章
- BZOJ.4919.[Lydsy1706月赛]大根堆(线段树合并/启发式合并)
题目链接 考虑树退化为链的情况,就是求一个最长(严格)上升子序列. 对于树,不同子树间是互不影响的.仿照序列上的LIS,对每个点x维护一个状态集合,即合并其子节点后的集合,然后用val[x]替换掉第一 ...
- 【BZOJ4919】[Lydsy六月月赛]大根堆 线段树合并
[BZOJ4919][Lydsy六月月赛]大根堆 Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切 ...
- bzoj4919 [Lydsy1706月赛]大根堆
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
- BZOJ4919:[Lydsy1706月赛]大根堆(set启发式合并)
Description 给定一棵n个节点的有根树,编号依次为1到n,其中1号点为根节点.每个点有一个权值v_i. 你需要将这棵树转化成一个大根堆.确切地说,你需要选择尽可能多的节点,满足大根堆的性质: ...
- BZOJ4919 [Lydsy1706月赛]大根堆 【dp + 启发式合并】
题目链接 BZOJ4919 题解 链上的\(LIS\)维护一个数组\(f[i]\)表示长度为\(i\)的\(LIS\)最小的结尾大小 我们可以用\(multiset\)来维护这个数组,子树互不影响,启 ...
- bzoj 4919 [Lydsy1706月赛]大根堆 set启发式合并+LIS
4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 599 Solved: 260[Submit][Stat ...
- [Lydsy1706月赛]大根堆
4919: [Lydsy1706月赛]大根堆 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 358 Solved: 150[Submit][Stat ...
- BZOJ 4919: [Lydsy1706月赛]大根堆 启发式合并
我不会告诉你这是线段树合并的好题的... 好吧我们可以搞一个multiset在dfs时求出LIS(自带二分+排序)进行启发式合并,轻松加愉悦... #include<cstdio> #in ...
- BZOJ 4919: [Lydsy1706月赛]大根堆
F[x][i]表示x的子树中取的数字<=i的最大值,线段树合并优化DP 写得很难看,并不知道好看的写法 #include<cstdio> #include<algorithm& ...
随机推荐
- 自定义cs程序安装界面
http://www.crifan.com/achieve_fixed_install_path_while_install_software_when_make_msi_installer/ 制作C ...
- linux traceroute追踪路由路径
TraceRoute的工作原理 1.TraceRoute的工作原理: traceroute 有使用两种:使用ICMP的和使用UDP的.Microsoft 使用ICMP,所以win9 ...
- 浅谈 Xamarin Community Toolkit 的未来发展
.NET MAUI会在今年晚些时候发布,我们也很高兴和大家一起分享我们对Xamarin Community Toolkit的计划! 这包括 .NET MAUI Community Toolkit.Xa ...
- 学习PHP中Fileinfo扩展的使用
今天来学习的这个扩展其实现在也已经是标配的一个扩展了,为什么呢?因为 Laravel 框架在安装的时候它就是必须的一个扩展,没有打开它的话,连 Laravel 框架都是无法使用的. Fileinfo ...
- symfony2已有数据表导入实体时报错 Doctrine does not support reverse engineering from tables that don't have a primary key
先在配置文件 app/config/config.yml中配置 schema_filter: /^(?!(tablename))/ 即可,或者在出现问题表都加上一个id 然后再使用命令 php app ...
- Jmeter扩展组件开发(3) - 实现方法
继承JavaSamplerClient,四种实现方法讲解 前提 JavaSamplerClient要把四种实现方法都继承,编译器才不会报错. com.demo(package包)右键新建一个secon ...
- PHP ASCII 排序方法
//自定义ascii排序function ASCII($params = array()){ if(!empty($params)){ $p = ksort($params); if($p){ $st ...
- 鸿蒙内核源码分析(汇编基础篇) | CPU在哪里打卡上班? | 百篇博客分析OpenHarmony源码 | v22.01
百篇博客系列篇.本篇为: v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在哪里打卡上班 | 51.c.h .o 硬件架构相关篇为: v22.xx 鸿蒙内核源码分析(汇编基础篇) | CPU在 ...
- C# 显示、隐藏窗口对应的任务栏
WPF中全屏窗口,会自动隐藏任务栏. 那非全屏窗口如何隐藏任务栏?甚至有没有一种场景,隐藏任务后自定义一套系统任务栏来显示? 以下会分阶段讲述一些概念 1. 主屏任务栏 任务栏,其实也是一个窗口,主屏 ...
- 域名系统-DNS
域名系统DNS 域名系统DNS(Domain Name System)是互联网使用的命名系统,用来把便于人们使用的机器名转化为IP地址,域名系统就是名字系统. 很多应用层的软件经常直接使用DNS.DN ...