P4577 [FJOI2018] 领导集团问题
容易写出 \(\mathcal O(n^2)\) 的 \(dp\):设 \(f_{u,i}\) 表示在 \(u\) 的子树内选数,最小的数是 \(i\) 能选最多的个数。转移:\(f_{u,\min(i,j)}=\max(f_{u,i}+f_{v,j})\)。
考虑把 \(u\) 选上 \(f_{u,w_u}=1+max_{j\geq w_u}(f_{u,j})\)。
使用线段树合并优化,\(merge\) 的时候维护一下 \(f_u\) 和 \(f_v\) 的后缀 \(max\) 即可。
一些细节:\(merge\) 时如果两个节点中有一个是空的,那么需要打一个区间加的懒标记,但是懒标记下穿时不能新建子节点,因为这样会导致 \(merge\) 边下穿懒标记边遍历,让复杂度假掉。仔细观察后发现如果一个点的儿子是空的话,这个点的懒标记对空儿子是无效的。
代码
/*
Luogu P4577 [FJOI2018] 领导集团问题
2026-03-20
*/
#include<bits/stdc++.h>
using namespace std;
namespace IO{
template<typename T>
inline void read(T&x){
x=0;char c=getchar();bool f=0;
while(!isdigit(c)) c=='-'?f=1:0,c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
f?x=-x:0;
}
template<typename T>
inline void write(T x){
if(x==0){putchar('0');return ;}
x<0?x=-x,putchar('-'):0;short st[50],top=0;
while(x) st[++top]=x%10,x/=10;
while(top) putchar(st[top--]+'0');
}
inline void read(char&c){c=getchar();while(isspace(c)) c=getchar();}
inline void write(char c){putchar(c);}
inline void read(string&s){s.clear();char c;read(c);while(!isspace(c)&&~c) s+=c,c=getchar();}
inline void write(string s){for(int i=0,len=s.size();i<len;i++) putchar(s[i]);}
template<typename T>inline void write(T*x){while(*x) putchar(*(x++));}
template<typename T,typename...T2> inline void read(T&x,T2&...y){read(x),read(y...);}
template<typename T,typename...T2> inline void write(const T x,const T2...y){write(x),putchar(' '),write(y...),sizeof...(y)==1?putchar('\n'):0;}
}using namespace IO;
const int maxn=200010;
int n,w[maxn],p[maxn];
vector<int>e[maxn];
class Segment_Tree{
private:
struct node{
int ch[2],max,lan;
node(){max=0;}
}t[maxn*40];
int rt[maxn],cnt;
void add_tag(int u,int z){if(u) t[u].lan+=z,t[u].max+=z;}
void up(int u){t[u].max=max({t[t[u].ch[0]].max,t[t[u].ch[1]].max});}
void down(int u){
add_tag(t[u].ch[0],t[u].lan),add_tag(t[u].ch[1],t[u].lan);
t[u].lan=0;
}
void insert(int&u,int l,int r,int d,int z){
if(l>d||r<d) return ;
if(u==0) u=++cnt;
if(l==r){t[u].max=max(t[u].max,z);return ;}
down(u);
int mid=l+r>>1;
insert(t[u].ch[0],l,mid,d,z),insert(t[u].ch[1],mid+1,r,d,z);
up(u);
}
void merge(int&u,int uu,int max1,int max2,int l,int r){
if(!u&&!uu) return ;
if(!u){u=uu;add_tag(u,max1);return ;}
if(!uu){add_tag(u,max2);return ;}
if(l==r){max1=max(max1,t[u].max),max2=max(max2,t[uu].max);t[u].max=max1+max2;return ;}
int mid=l+r>>1;
down(u),down(uu);
int nmax1=max(max1,t[t[u].ch[1]].max);
int nmax2=max(max2,t[t[uu].ch[1]].max);
merge(t[u].ch[0],t[uu].ch[0],nmax1,nmax2,l,mid);
merge(t[u].ch[1],t[uu].ch[1],max1,max2,mid+1,r);
up(u);
}
int query(int u,int l,int r,int ll,int rr){
if(u==0) return 0;
if(l>rr||r<ll) return 0;
if(ll<=l&&r<=rr) return t[u].max;
down(u);
int mid=l+r>>1;
int ans=max(query(t[u].ch[0],l,mid,ll,rr),query(t[u].ch[1],mid+1,r,ll,rr));
up(u);
return ans;
}
public:
void insert(int id,int d,int z){insert(rt[id],1,n,d,z);}
void merge(int id,int idd){merge(rt[id],rt[idd],0,0,1,n);}
int query(int u){return t[rt[u]].max;}
int query(int id,int l,int r){return query(rt[id],1,n,l,r);}
}t;
void dfs(int u){
for(int v:e[u]) dfs(v);
for(int v:e[u]) t.merge(u,v);
int z=t.query(u,w[u],n)+1;
t.insert(u,w[u],z);
}
signed main(){
read(n);
for(int i=1;i<=n;i++) read(w[i]),p[i]=w[i];
sort(p+1,p+1+n);
int cnt_p=unique(p+1,p+1+n)-p-1;
for(int i=1;i<=n;i++) w[i]=lower_bound(p+1,p+1+cnt_p,w[i])-p;
for(int i=2;i<=n;i++){
int fa;read(fa);
e[fa].push_back(i);
}
dfs(1);
write(t.query(1));
return 0;
}

浙公网安备 33010602011771号