「题解报告」P4577 [FJOI2018]领导集团问题
题解 P4577 [FJOI2018]领导集团问题
题解区好像没有线段树上又套了二分的做法,于是就有了这片题解。
怀着必 WA 的决心交了两发,一不小心就过了。
题意
求一个树上最长不下降子序列。
思路
首先考虑裸的 dp:设 \(f_{u,j}\) 表示以 \(u\) 为根的子树里选的数的最大值不小于 \(j\) 能选多少个。
\begin{cases}
\sum_\limits{v\ is\ u's\ son}f_{v,j} &j>w_u\\
\max\{\sum_\limits{v\ is\ u's\ son}f_{v,j},\sum_\limits{v\ is\ u's\ son}f_{v,j+1}+1\} &j\le w_u
\end{cases}
\]
接下来是如何优化:
在 DFS 每个节点的过程中,用权值线段树维护 \(f_{u,j}\)。
首先把所有儿子的权值线段树和起来。
然后考虑在什么区间选上这个节点更优。
右端点肯定是 \(w_i\) ,那么我们二分求左端点,即二分一个最小的选了比不选更优的点。
单点查询用权值线段树,合并儿子们的树用线段树合并,区间修改用标记可持久化。
时间复杂度是 \(O(nlog^2n)\)。
虽然慢到起飞但是能过。
代码
#include<bits/stdc++.h>
#define _for(i,a,b) for(int i=a;i<=b;++i)
#define for_(i,a,b) for(int i=a;i>=b;--i)
#define ll long long
#define bdmd int mid=(l+r)>>1
using namespace std;
const int N=2e5+10,inf=0x3f3f3f3f;
int n,cnt,w[N];
vector<int>son[N];
inline int rnt(){
int x=0,w=1;char c=getchar();
while(!isdigit(c)){if(c=='-')w=-1;c=getchar();}
while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*w;
}
namespace LISAN{
int ls[N];
void LiSan(){
_for(i,1,n){
ls[i]=w[i];
}
sort(ls+1,ls+n+1);
cnt=unique(ls+1,ls+n+1)-ls-1;
_for(i,1,n)
w[i]=lower_bound(ls+1,ls+cnt+1,w[i])-ls;
return;
}
}
class ValSegmentTree{
public:
int root[N],tot,uucnt,un_use[N*40];
class TREE{
public:
int left_son,right_son;
int val=0;
}tree[N*40];
const TREE NONE=(TREE){0,0,0};
#define ls(p) tree[p].left_son
#define rs(p) tree[p].right_son
#define l_s(p) tree[p].left_son,l,mid
#define r_s(p) tree[p].right_son,mid+1,r
#define va(p) tree[p].val
#define bdmd int mid=(l+r)>>1
inline int NewP(){
if(uucnt)
return un_use[uucnt--];
return ++tot;
}
inline void DeleteP(int p){
tree[p]=NONE;
un_use[++uucnt]=p;
return;
}
void UpdateQJ(int &p,int l,int r,int le,int ri,int val){
if(!p)p=NewP();
if(ri<l||r<le)return;
if(le<=l&&r<=ri)
va(p)+=val;
else{
bdmd;
UpdateQJ(l_s(p),le,ri,val);
UpdateQJ(r_s(p),le,ri,val);
}
}
int QueryP(int p,int l,int r,int x){
if(!p)return 0;
if(l==r)return va(p);
else{
bdmd;
if(x<=mid)
return va(p)+QueryP(l_s(p),x);
else
return va(p)+QueryP(r_s(p),x);
}
}
void Merge(int &p1,int p2){
if(!p1){p1=p2;return;}
if(!p2){return;}
va(p1)+=va(p2);
Merge(ls(p1),ls(p2));
Merge(rs(p1),rs(p2));
DeleteP(p2);
return;
}
#undef ls
#undef rs
#undef l_s
#undef r_s
#undef va
}tr;
void Dfs(int u,int father){
int sz=son[u].size();
_for(i,0,sz-1){
int v=son[u][i];
if(v==father)continue;
Dfs(v,u);
tr.Merge(tr.root[u],tr.root[v]);
}
int xuan=tr.QueryP(tr.root[u],1,cnt,w[u]+1)+1;
int l=1,r=w[u];
while(l<=r){
bdmd;
if(tr.QueryP(tr.root[u],1,cnt,mid)>=xuan)
l=mid+1;
else
r=mid-1;
}
tr.UpdateQJ(tr.root[u],1,cnt,l,w[u],1);
return;
}
int main(){
n=rnt();
_for(i,1,n)w[i]=rnt();
LISAN::LiSan();
_for(i,2,n){
int x=rnt();
son[i].push_back(x);
son[x].push_back(i);
}
Dfs(1,0);
printf("%d\n",tr.QueryP(tr.root[1],1,n,1));
return 0;
}
「题解报告」P4577 [FJOI2018]领导集团问题的更多相关文章
- P4577 [FJOI2018]领导集团问题
P4577 [FJOI2018]领导集团问题 我们对整棵树进行dfs遍历,并用一个multiset维护对于每个点,它的子树可取的最大点集. 我们遍历到点$u$时: 不选点$u$,显然答案就为它的所有子 ...
- 「题解报告」 P3167 [CQOI2014]通配符匹配
「题解报告」 P3167 [CQOI2014]通配符匹配 思路 *和?显然无法直接匹配,但是可以发现「通配符个数不超过 \(10\) 」,那么我们可以考虑分段匹配. 我们首先把原字符串分成多个以一个通 ...
- 「题解报告」P2154 虔诚的墓主人
P2154 虔诚的墓主人 题解 原题传送门 题意 在 \(n\times m\) 一个方格上给你 \(w\) 个点,求方格里每个点正上下左右各选 \(k\) 个点的方案数. \(1 \le N, M ...
- 「题解报告」SP16185 Mining your own business
题解 SP16185 Mining your own business 原题传送门 题意 给你一个无向图,求至少安装多少个太平井,才能使不管那个点封闭,其他点都可以与有太平井的点联通. 题解 其他题解 ...
- 「题解报告」Blocks
P3503 Blocks 题解 原题传送门 思路 首先我们可以发现,若 \(a_l\) ~ \(a_r\) 的平均值大于等于 \(k\) ,则这个区间一定可以转化为都大于等于 \(k\) 的.我们就把 ...
- 「题解报告」P3354
P3354 题解 题目传送门 一道很恶心的树形dp 但是我喜欢 题目大意: 一片海旁边有一条树状的河,入海口有一个大伐木场,每条河的分叉处都有村庄.建了伐木场的村庄可以直接处理木料,否则要往下游的伐木 ...
- 「题解报告」CF1067A Array Without Local Maximums
大佬们的题解都太深奥了,直接把转移方程放出来让其他大佬们感性理解,蒟蒻们很难理解,所以我就写了一篇让像我一样的蒟蒻能看懂的题解 原题传送门 动态规划三部曲:确定状态,转移方程,初始状态和答案. --神 ...
- 洛谷P4577 [FJOI2018]领导集团问题(dp 线段树合并)
题意 题目链接 Sol 首先不难想到一个dp,设\(f[i][j]\)表示\(i\)的子树内选择的最小值至少为\(j\)的最大个数 转移的时候维护一个后缀\(mx\)然后直接加 因为后缀max是单调不 ...
- 「题解报告」P7301 【[USACO21JAN] Spaced Out S】
原题传送门 神奇的5分算法:直接输出样例. 20分算法 直接把每个点是否有牛的状态DFS一遍同时判断是否合法,时间复杂度约为\(O(2^{n^2})\)(因为有判断合法的剪枝所以会比这个低).而在前四 ...
随机推荐
- 测试人生 | 薪资翻倍涨至50W是种什么样的体验?
本文为霍格沃兹测试开发学社优秀学员跳槽笔记,测试开发进阶学习文末加群. 本人已经工作7年了,做的都是功能测试以及写一些简单的自动化脚本,加上之前没有学习的意识,导致专业技术水平与工作年限不匹配,在上家 ...
- MySQL-常用数据库操作SQL汇总
更新记录 2022年6月15日 发布. 2022年6月11日 将笔记迁移到博客中. 连接与字符设置 设置连接字符类型 SET CHARACTER SET 'utf8'; 或者 SET NAMES ut ...
- 02 RESTFul接口和HTTP的幂等性分析
RESTFul接口和HTTP的幂等性分析 REST全称是Representational State Transfer,中文为表述性状态转移,REST指的是一组架构约束条件和原则 RESTful表述的 ...
- jetbrains 系列产品无限试用
无限试用插件 在线安装 需要添加第三方插件仓库地址 设置 -- Manage Plugins Reposition... -- + https://plugins.zhile.io plugins 中 ...
- python+anaconda+pycharm的使用
研一开学的时候开始接触了这些,但是对于其各种功能感到十分混乱,现在通过这篇博文将其功能详细的写出来. 1.python解释器 首先要了解python解释器,我们俗称的下载python也就是下载pyth ...
- sort基本用法
sort 选项 -u --去除重复行 -r --降序排列,默认是升序 -o --由于sort默认是把结果输出到标准输出,所以需要用重定向才能将结果写入文件,形如sort filename > n ...
- NC16430 [NOIP2016]蚯蚓
NC16430 [NOIP2016]蚯蚓 题目 题目描述 本题中,我们将用符号 \(\lfloor c \rfloor\) 表示对 c 向下取整,例如:\(\lfloor 3.0 \rfloor = ...
- 使用dnSpy对无源码EXE或DLL进行反编译并且修改
背景 总有一些特殊情况,我们没有源码,但是某个C#程序集dll或者可执行程序exe影响到我们代码的正常运行,我们希望得到源码,能改掉或者修改某些bug,但是苦于没有源码,这个时候可以用dnspy进行源 ...
- JavaScript知识梳理
JS内功修炼 专业术语 类,封装,继承, 专业术语 babel 块级作用域 函数 扩展对象的功能性 解构 set和map js的类 改进的数组功能 Promise与异步编程 代理和反射 用模块封装代码 ...
- Linux查看内网服务器的出口IP
查看内网服务器的出口IPcurl ifconfig.me [root@vpnserver ~]# curl ifconfig.me111.10.100.100 [root@vpnserver ~]#