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& ...
随机推荐
- 255 day03_List、Set、数据结构、Collections
day03 [List.Set.数据结构.Collections] 主要内容 数据结构 List集合 Set集合 Collections 教学目标 [ ] 能够说出List集合特点 [ ] 能够说出常 ...
- 求1+2+…+n
求 1+2+...+n ,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 示例 1: 输入: n = 3 输出: 6 示例 2: ...
- 洛谷P1125——笨小猴(简易模拟)
https://www.luogu.org/problem/show?pid=1125 题目描述 笨小猴的词汇量很小,所以每次做英语选择题的时候都很头疼.但是他找到了一种方法,经试验证明,用这种方法去 ...
- 数据结构逆向分析-Map
数据结构逆向分析-Map map是一个典型的二叉树结构,准确的来说是一个平衡二叉树或者红黑树,特点是数据存储是有序的存储. 参考侯杰老师的stl源码剖析,map里面采用的是RB-TREE也就是红黑树 ...
- 一文详解JavaScript的继承模式
1 原型链继承 #### ES6中通过原型继承多个引用类型的属性和方法,由于原型和实例的关系,即每个构造函数都有自己的原型对象,同时原型有一个属性指向构造函数,并且实例有一个内部的指针指向原型.如果存 ...
- 创建一个新的解耦的Orchard Core CMS网站
引言本文将介绍创建一个功能齐全.解耦的CMS网站的过程,该网站允许您编辑博客帖子并呈现它们.解耦是一种开发模型,其中站点的前端和后端(管理)托管在同一个Web应用程序中,但只有后端由CMS驱动.然后, ...
- xmind使用技巧
xmind看似每个人都会使用,但是掌握一些小技巧,能够有效提升工作效率. 多行复制粘贴 在xmind中选中多行,复制然后可以直接粘贴到excel.word当中. 在excel.word选中多行,复制然 ...
- Oracle基本入门
一.数据的存储 1.java 程序中的对象:数组.集合保存.当运行的程序结束的时候,里面的数据就消亡. 2.文件存储系统: 存在的缺陷: 2.1)没有明确的数据类型划分. 2.2)没有用户身份验证机制 ...
- [转载]PHP命名规则
PHP命名规则 引用地址:http://www.cnblogs.com/pengxl/p/3571157.html 就一般约定而言,类.函数和变量的名字应该是能够让代码阅读者能够容易地知道这些代码的作 ...
- Spring Cloud Gateway 没有链路信息,我 TM 人傻了(下)
本系列是 我TM人傻了 系列第五期[捂脸],往期精彩回顾: 升级到Spring 5.3.x之后,GC次数急剧增加,我TM人傻了 这个大表走索引字段查询的 SQL 怎么就成全扫描了,我TM人傻了 获取异 ...