首先$dfs$一遍,记录每个节点的$dfs$序和其子树大小。
$p[i]$经离散化处理后按照$dfs$序的顺序建立主席树,每个节点的求解即为其子树内$p$值小于该节点的节点数。
主席数差分查询即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+5;
int n,m,x,a[maxn],b[maxn],T[maxn];
int sum[maxn<<5],L[maxn<<5],R[maxn<<5];
int cnt,head[maxn],siz[maxn],pos[maxn],rk[maxn],tot;
struct Edge{
int to,next;
}e[maxn];
void add(int u,int v) {
e[++cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
}
void dfs(int u) {
siz[u]=1;
pos[u]=++tot;
rk[tot]=u;
for(int i=head[u];i;i=e[i].next) {
int v=e[i].to;
dfs(v);
siz[u]+=siz[v];
}
}
int build(int l,int r) {
int rt=++tot;
if(l<r) {
int mid=l+r>>1;
L[rt]=build(l,mid),R[rt]=build(mid+1,r);
}
return rt;
}
int update(int pre,int l,int r,int pos) {
int rt=++tot;
L[rt]=L[pre],R[rt]=R[pre],sum[rt]=sum[pre]+1;
if(l<r) {
int mid=l+r>>1;
if(pos<=mid) L[rt]=update(L[pre],l,mid,pos);
else R[rt]=update(R[pre],mid+1,r,pos);
}
return rt;
}
int query(int u,int v,int l,int r,int L_,int R_) {
if(L_<=l&&R_>=r) return sum[v]-sum[u];
int mid=l+r>>1,res=0;
if(L_<=mid) res+=query(L[u],L[v],l,mid,L_,R_);
if(R_>mid) res+=query(R[u],R[v],mid+1,r,L_,R_);
return res;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n),m=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;++i) a[i]=lower_bound(b+1,b+1+n,a[i])-b;
for(int i=2;i<=n;++i) scanf("%d",&x),add(x,i);
dfs(1);
tot=0;
T[0]=build(1,m);
for(int i=1;i<=n;++i) T[i]=update(T[i-1],1,m,a[rk[i]]);
for(int i=1;i<=n;++i) printf("%d
",query(T[pos[i]],T[pos[i]+siz[i]-1],1,m,a[i]+1,m));
return 0;
}