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& ...
随机推荐
- DOM对象入门
1.概念 2.script最好是放在后面,等html的文档内容加载完毕,不然获取不到 3.事件基本操作 第一种绑定事件html和js耦合度高,用第二种 4.灯开关事件使用
- 页面调用系统window打印
一. 打印:直接页面调用window.print(),当前页面就会转换成打印页面 当前页面是使用HTML拼接成A4纸表格样式的展示: doPrint:function(type) { // this. ...
- 在springboot pom文件配置过程,`spring-boot-maven-plugin`配置出错的问题解决及配置过程出现问题的一些思考
在springboot pom文件配置过程,spring-boot-maven-plugin配置出错的问题解决及配置过程出现问题的一些思考 解决方法一: 也是最简单的方法,可能是maven没有来得及导 ...
- Sentry 监控 - Discover 事件大数据查询分析引擎
系列 1 分钟快速使用 Docker 上手最新版 Sentry-CLI - 创建版本 快速使用 Docker 上手 Sentry-CLI - 30 秒上手 Source Maps Sentry For ...
- pip国内源设置
在目录 C:\Users\Administrator下新建pip目录 C:\Users\Administrator\pip 添加 pip.ini 文件 pip.ini内容设置为 [global] in ...
- Django学习day05随堂笔记
每日测验 """ 今日考题 1.反向解析的本质是什么,无名和有名反向解析如何操作? 2..路由分发能够实现的前提是什么,需要注意什么,名称空间什么时候使用 3..什么是虚 ...
- PHP中的对象比较
在之前的文章中,我们讲过PHP中比较数组的时候发生了什么?.这次,我们来讲讲在对象比较的时候PHP是怎样进行比较的. 首先,我们先根据PHP文档来定义对象比较的方式: 同一个类的实例,比较属性大小,根 ...
- Centos6.8阿里云linux系统下配置LAMP运行环境-mysql5.6
1.Apache #安装apache软件 yum -y install httpd #启动httpd服务 service httpd start #设置开机启动chkconfig --list htt ...
- axios的简单的使用
Axios 是什么? Axios 是一个基于 promise 网络请求库,作用于node.js 和浏览器中. 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中).在服务端 ...
- MySQL 服务无法启动。 服务没有报告任何错误。 请键入 NET HELPMSG 3534 以获得更多的帮助。
第一步 有一部分人成功了在安装根目录创建data文件夹 第二步 有一部分人成功了D:\Program Files\mysql\bin>mysqld initialize 第三步 这步之后我安装成 ...