蒟蒻的垂死挣扎
第一篇当然是模板题啦。
对每一个点开一棵线段树,动态开点,合并的时候同样动态开点总和信息即可。
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#define ll long long
#define MOD 1000000007
#define N 110000
#define RG register
using namespace std;
inline ll read(){
RG ll x=0,o=1; RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=((x<<3)+(x<<1))+ch-'0',ch=getchar();
return x*o;
}
int n,yyb[N],len,p[N],root[N],top,first[N],ans[N];
struct mona { int nxt,en; } s[N<<1];
inline void Insert(int x,int y) { s[++top]=(mona) { first[x],y },first[x]=top; }
struct SegTree {
int tot,ls[N*80],rs[N*80],num[N*80];
inline void Build(int l,int r,int &x,int val){
x=++tot,++num[x]; if(l==r) return ;
int mid=(l+r)>>1;
if(val<=mid) Build(l,mid,ls[x],val);
else Build(mid+1,r,rs[x],val);
}
inline int Query(int l,int r,int now,int L,int R){
if(l>=L&&r<=R) return num[now]; if(L>R) return 0;
int mid=(l+r)>>1,ans=0;
if(L<=mid) ans+=Query(l,mid,ls[now],L,R);
if(R>mid) ans+=Query(mid+1,r,rs[now],L,R);
return ans;
}
inline int Union(int u,int v){
if(!u||!v) return u+v;
int t=++tot; num[t]=num[u]+num[v];
ls[t]=Union(ls[u],ls[v]);
rs[t]=Union(rs[u],rs[v]);
return t;
}
} T;
inline void Orz(){
sort(yyb+1,yyb+1+len);
len=unique(yyb+1,yyb+1+len)-yyb-1;
for(RG int i=1;i<=n;++i) p[i]=lower_bound(yyb+1,yyb+1+len,p[i])-yyb;
}
inline void Dfs(int k,int fa){
for(RG int i=first[k];i;i=s[i].nxt){
int en=s[i].en; if(en==fa) continue ;
Dfs(en,k),root[k]=T.Union(root[k],root[en]);
} ans[k]+=T.Query(1,len,root[k],p[k]+1,len);
}
int main(){
n=len=read(); for(RG int i=1;i<=n;++i) p[i]=yyb[i]=read();
Orz(); for(RG int i=1;i<=n;++i) T.Build(1,len,root[i],p[i]);
for(RG int i=1;i<n;++i){
int x=read(); Insert(x,i+1),Insert(i+1,x);
} Dfs(1,0);
for(RG int i=1;i<=n;++i) printf("%d\n",ans[i]);
}