「题解报告」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})\)(因为有判断合法的剪枝所以会比这个低).而在前四 ...
随机推荐
- ABAP CDS DDHEADANNO
- 利用kubernetes资源锁完成自己的HA应用
Backgroud 前一章中,对kubernetes的选举原理进行了深度剖析,下面就通过一个example来实现一个,利用kubernetes提供的选举机制完成的高可用应用. 对于此章需要提前对一些概 ...
- 6 分钟看完 BGP 协议。
上一篇文章见 万字长文爆肝路由协议! 上面我们聊 RIP .OSPF 协议都是基于 AS 即自治系统内的协议,可以把它们认为是域内路由协议:而下面我们要聊的就是 AS 之间的协议了,这也叫做域间路由协 ...
- Codeforces Round #801 (Div. 2)
题集链接 A Subrectangle Guess 代码 #include <bits/stdc++.h> #define endl "\n" using namesp ...
- 循环结构-for循环和while循环
循环语句1--for for循环语句格式: for(初始化表达式①; 布尔表达式②; 步进表达式④){ 循环体③ } 执行流程 执行顺序:①②③④>②③④>②③④-②不满足为止. ①负责完 ...
- 自动登录token过期问题
之前遇到的一个也不算棘手的问题,自动登录本地存储了token却无法登录到主页. 先说一下我自动登录的思路:在用户登录成功时,将 token 存入 cookie :当用户下次来到本网站,读取 cooki ...
- 市面上的工业ERP系统如何区别?存在什么样的不同?
工业发展当中所要涉及到的管理是繁琐而复杂的,在ERP系统的拓展开发中,市面上出现了很多的工业ERP系统来让企业选择.这是近年来非常受欢迎的一种管理手段,依靠计算机系统的强大功能,来实现数据化的管理,企 ...
- Java开发学习(十五)----AOP入门案例及其工作流程解析
一.AOP简介 1.1 什么是AOP AOP(Aspect Oriented Programming)面向切面编程,一种编程范式,指导开发者如何组织程序结构. OOP(Object Oriented ...
- 2022-7-18 第五组 pan 面向对象
面向过程 向过程就是:面向过程,其实就是面向着具体的每一个步骤和过程,把每一个步骤和过程完成,然后由这些功能方法相互调用,完成需求. 面向对象 什么是面向对象: 面向对象思想就是不断的创建对象,使用对 ...
- .NET的求复杂类型集合的差集、交集、并集
前言 如标题所述,在ASP.NET应用程序开发中,两个集合做比较时 我们使用微软IEnumerable封装的 Except/Intersect/Union 取 差集/交集/并集 方法是非常的方便的: ...