Part 0
由这题,可以联想到最长不下降子序列。对于每个节点,我们定义DP[i]为这个子树内所有节点堆顶元素等于i时的最大的堆的大小。我们可以把这个数组放在线段树上维护。线段树的叶子节点存的就是DP[i]。线段树节点[L—R]存的是这段区间DP值的最大值。
Part 1
线段树合并时就可以一直更新这个DP数组。由于每个子节点是互不干扰的,故合并时记录两颗线段树前面的DP最大值。(若当前操作区间为[L—R],那么我们分别记录两颗线段树内DP[1—L-1]的最大值,这可以作为参数向下传)若有一颗线段树为空,则把另一颗线段树DP[1—L-1]的最大值加上去(用懒惰标记)若两颗线段树有相同的叶子节点,那么直接合并即可(即DP数组相加,同时两个DP值要分别与[1—L]的DP值的最大值的取一个max)。
加入当前节点的状态转移方程为DP[i]=MAX(DP[1—i-1])+1。同样是在Updata将DP[1—L]的最大值作为参数向下传。
最后答案就是根节点的答案。
注意初始对权值要离散化。
Part 2
复杂度的话就是初始建树+线段树合并的复杂度。
AC代码:
#include<cstdio>
#include<algorithm>
#define M 200005
using namespace std;
void check_max(int &x,int y){if(x<y)x=y;}
void check_min(int &x,int y){if(x>y)x=y;}
int id;
struct E{
int to,nx;
}edge[M<<1];
int tot,head[M];
void Addedge(int a,int b){
edge[++tot].to=b;
edge[tot].nx=head[a];
head[a]=tot;
}
int tot_id;
int Root[M],Lson[M*20],Rson[M*20];
int mx[M*20],Add[M*20];
void Down(int tid){//懒惰标记
if(Lson[tid]){
mx[Lson[tid]]+=Add[tid];
Add[Lson[tid]]+=Add[tid];
}
if(Rson[tid]){
mx[Rson[tid]]+=Add[tid];
Add[Rson[tid]]+=Add[tid];
}
Add[tid]=0;
}
void Up(int tid){
mx[tid]=max(mx[Lson[tid]],mx[Rson[tid]]);
}
void Updata(int L,int R,int x,int &tid,int Lmx=0){//Lmx为DP[1---L]的DP值的最大值
if(!tid)tid=++tot_id;//动点线段树
if(L==R){
check_max(mx[tid],Lmx+1);
return;
}
Down(tid);
int mid=(L+R)>>1;
if(x<=mid)Updata(L,mid,x,Lson[tid],Lmx);
else Updata(mid+1,R,x,Rson[tid],max(Lmx,mx[Lson[tid]]));
Up(tid);
}
int val[M],fa[M];
void Merge(int &x,int y,int L,int R,int XLmx=0,int YLmx=0){
//XLmx为X这颗线段树的DP[1---L]的最大值,YLmx为Y这颗线段树的DP[1---L]的最大值
if(!x&&!y)return;
if(!y){
mx[x]+=YLmx;
Add[x]+=YLmx;//懒惰标记的更新
x+=y;
return;
}
if(!x){
mx[y]+=XLmx;
Add[y]+=XLmx;
x+=y;
return;
}
if(L==R){
check_max(XLmx,mx[x]);//先取max
check_max(YLmx,mx[y]);
mx[x]=XLmx+YLmx;//再更新
return;
}
int mid=(L+R)>>1;
Down(x),Down(y);
Merge(Rson[x],Rson[y],mid+1,R,max(XLmx,mx[Lson[x]]),max(YLmx,mx[Lson[y]]));//只有在询问右区间时才更新XLmx与YLmx
Merge(Lson[x],Lson[y],L,mid,XLmx,YLmx);//这段语句必须在下面,因为上面更新XLmx与YLmx所需的都是老的mx数组中的值而非更新之后的。
Up(x);
}
void dfs(int now){
for(int i=head[now];i;i=edge[i].nx){
int nxt=edge[i].to;
if(nxt==fa[now])continue;
dfs(nxt);
Merge(Root[now],Root[nxt],1,id);//都先向上合并
}
Updata(1,id,val[now],Root[now]);
}
int C[M];
int main(){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d",&val[i],&fa[i]);
Addedge(fa[i],i);
C[i]=val[i];
}
sort(C+1,C+n+1);
id=unique(C+1,C+n+1)-C-1;
for(int i=1;i<=n;i++)val[i]=lower_bound(C+1,C+id+1,val[i])-C;//离散化
dfs(1);
printf("%d\n",mx[Root[1]]);
return 0;
}