​https://www.lydsy.com/JudgeOnline/problem.php?id=4756​

主席树裸题 这里考虑线段树合并

还是对树图的每个点建立只有一条链的线段树 然后在dfs回溯时将所有子树的线段树合并 然后区间查询一下就好

 

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
const int maxm=2e6+10;

struct node
{
int v,next;
};

node edge[2*maxn];
int lef[maxm],rgt[maxm],val[maxm];
int ary[maxn],tmp[maxn],first[maxn],root[maxn],ans[maxn];
int n,num;

void addedge(int u,int v)
{
edge[num].v=v;
edge[num].next=first[u];
first[u]=num++;
}

void pushup(int cur)
{
val[cur]=val[lef[cur]]+val[rgt[cur]];
}

void update(int &cur,int tar,int l,int r)
{
int m;
if(!cur) cur=++num;
if(l==r){
val[cur]=1;
return;
}
m=(l+r)/2;
if(tar<=m) update(lef[cur],tar,l,m);
else update(rgt[cur],tar,m+1,r);
pushup(cur);
}

int query(int pl,int pr,int l,int r,int cur)
{
int res,m;
if(pl<=l&&r<=r) return val[cur];
res=0,m=(l+r)/2;
if(pl<=m) res+=query(pl,pr,l,m,lef[cur]);
if(pr>m) res+=query(pl,pr,m+1,r,rgt[cur]);
return res;
}

int unite(int x,int y)
{
if(x==0) return y;
if(y==0) return x;
lef[x]=unite(lef[x],lef[y]);
rgt[x]=unite(rgt[x],rgt[y]);
pushup(x);
return x;
}

void dfs(int cur,int fa)
{
int i,v;
update(root[cur],ary[cur],1,n);
for(i=first[cur];i!=-1;i=edge[i].next){
v=edge[i].v;
if(v!=fa){
dfs(v,cur);
root[cur]=unite(root[cur],root[v]);
}
}
if(ary[cur]+1<=n) ans[cur]=query(ary[cur]+1,n,1,n,root[cur]);
}

int main()
{
int i,u,v;
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&ary[i]);
tmp[i]=ary[i];
}
sort(tmp+1,tmp+n+1);
for(i=1;i<=n;i++) ary[i]=lower_bound(tmp+1,tmp+n+1,ary[i])-tmp;
memset(first,-1,sizeof(first));
num=0;
for(u=2;u<=n;u++){
scanf("%d",&v);
addedge(u,v),addedge(v,u);
}
num=0;
dfs(1,0);
for(i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}