题目大意:
n只奶牛构成了一个树形的公司,每个奶牛有一个能力值pi,1号奶牛为树根。
问对于每个奶牛来说,它的子树中有几个能力值比它大的。
思路:
用权值线段树来查询子树中比它大的结点有多少个。但是权值线段树需要不断地合并。
于是在递归的时候线段树合并就好了。
#include<bits/stdc++.h>
#define REP(i,a,b) for(int i=a;i<=b;++i)
#define mid ((l+r)>>1)
typedef long long ll;
using namespace std;
void File(){
freopen("bzoj4756.in","r",stdin);
freopen("bzoj4756.out","w",stdout);
}
const int maxn=1e5+10;
const int maxm=2e6+10;
int n,a[maxn],tot,ans[maxn];
int las[maxn<<1],to[maxn<<1],beg[maxn],cnte=1;
map<int,int>mp;
map<int,int>::iterator it;
int root[maxn],lc[maxm],rc[maxm],val[maxm],cnt;
void add(int u,int v){las[++cnte]=beg[u]; beg[u]=cnte; to[cnte]=v;}
void update(int &rt,int l,int r,int pos){
if(!rt)rt=++cnt;
if(l==r)++val[rt];
else{
if(pos<=mid) update(lc[rt],l,mid,pos);
else update(rc[rt],mid+1,r,pos);
val[rt]=val[lc[rt]]+val[rc[rt]];
}
}
int query(int rt,int l,int r,int L,int R){
if(!rt)return 0;
if(L<=l && r<=R)return val[rt];
int ret=0;
if(L<=mid)ret+=query(lc[rt],l,mid,L,R);
if(R>=mid+1)ret+=query(rc[rt],mid+1,r,L,R);
return ret;
}
int merge(int x,int y){
if(!x || !y)return x+y;
int now=++cnt;
val[now]=val[x]+val[y];
lc[now]=merge(lc[x],lc[y]);
rc[now]=merge(rc[x],rc[y]);
return now;
}
void dfs(int u){
for(int i=beg[u];i;i=las[i]){
dfs(to[i]);
root[u]=merge(root[u],root[to[i]]);
}
ans[u]=query(root[u],1,tot,a[u]+1,tot);
update(root[u],1,tot,a[u]);
}
int main(){
File();
scanf("%d",&n);
REP(i,1,n)scanf("%d",&a[i]),mp[a[i]]=0;
for(it=mp.begin();it!=mp.end();++it)
mp[it->first]=++tot;
REP(i,1,n)a[i]=mp[a[i]];
REP(i,2,n){
int f;
scanf("%d",&f);
add(f,i);
}
dfs(1);
REP(i,1,n)printf("%d\n",ans[i]);
return 0;
}