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& ...
随机推荐
- javaScript对象——function对象
1.基本对象和Function(函数)方法对象 2.概念 3.创建function对象的三种方式: 第一种不建议使用 2.3两种方式就是方法名位置不同,建议使用: 4.方法调用只要名字对,实参不一定完 ...
- jquery实现强制刷新
$('iframe.active').attr('src', $('iframe.active').attr('src'));
- 除PerfDog之外,还有什么性能测试工具。
除PerfDog之外,还有什么性能测试工具. 高通的Snapdragon Profiler 下载地址:https://developer.qualcomm.com/software/snapdrago ...
- HCNP Routing&Switching之路由控制-策略路由
前文我们了解了路由策略工具Route-Policy相关话题,回顾请参考https://www.cnblogs.com/qiuhom-1874/p/15322135.html:今天我们来聊一聊策略路由相 ...
- jqGride的基本使用
1. 定义:jqGrid是一个在jQuery基础上封装一个表格控件,以ajax的方式和服务器端通信. 2. 使用方式: 2.1 项目中引入jqGride的文件: 2.2 搭建开发页面: 2.3 构建 ...
- lua自写限制并发访问模块
注意:ngx.say跟ngx.exit是不可以共存,否则会出现ngx.exit无法正常执行 1.定义lua共享内存20m lua_shared_dict ceshi 20m; 2.再location ...
- P6657-[模板]LGV 引理
正题 题目链接:https://www.luogu.com.cn/problem/P6657 题目大意 给出$n\times n$的棋盘,$m$个起点第$i$个为$(1,a_i)$,对应$m$个终点第 ...
- Python读取ini配置文件(接口自动测试必备)
前言 大家应该接触过.ini格式的配置文件.配置文件就是把一些配置相关信息提取出去来进行单独管理,如果以后有变动只需改配置文件,无需修改代码. 特别是后续做自动化的测试,代码和数据分享,进行管理.比如 ...
- python OSError: [Errno 22] Invalid argument: '\u202aF://text
windows10 python3 读文件的时候报的错误 原因不明时好时坏很头疼但又没办法不知道怎么解决,网上的说法都不能解决,
- RuntimeError: DataLoader worker (pid 18255) is killed by signal: Killed.
RuntimeError: DataLoader worker (pid 18255) is killed by signal: Killed. 通过观察内存发现,数据加载过程中内存会被耗尽.