题目描述
奶牛们又一次试图创建一家创业公司,还是没有从过去的经验中吸取教训--牛是可怕的管理者!
为了方便,把奶牛从 1 \cdots N(1 \leq N \leq 100, 000)1⋯N(1≤N≤100,000) 编号,把公司组织成一棵树,1 号奶牛作为总裁(这棵树的根节点)。除了总裁以外的每头奶牛都有一个单独的上司(它在树上的 “双亲结点”)。所有的第 ii 头牛都有一个不同的能力指数 p(i)p(i),描述了她对其工作的擅长程度。如果奶牛 ii 是奶牛 jj 的祖先节点(例如,上司的上司的上司),那么我们我们把奶牛 jj 叫做 ii 的下属。
不幸地是,奶牛们发现经常发生一个上司比她的一些下属能力低的情况,在这种情况下,上司应当考虑晋升她的一些下属。你的任务是帮助奶牛弄清楚这是什么时候发生的。简而言之,对于公司的中的每一头奶牛 ii,请计算其下属 jj 的数量满足 p(j) > p(i)p(j)>p(i)。
输入输出格式
输入格式:
输入的第一行包括一个整数 NN。
接下来的 NN 行包括奶牛们的能力指数 p(1) \cdots p(N)p(1)⋯p(N). 保证所有数互不相同,在区间 1 \cdots 10^91⋯109 之间。
接下来的 N-1N−1 行描述了奶牛 2 \cdots N2⋯N 的上司(双亲节点)的编号。再次提醒,1 号奶牛作为总裁,没有上司。
输出格式:
输出包括 NN 行。输出的第 ii 行应当给出有多少奶牛 ii 的下属比奶牛 ii 能力高。
输入输出样例
输入样例#1:
5
804289384
846930887
681692778
714636916
957747794
1
1
2
3
输出样例#1:
2
0
1
0
0
树上的树状数组或线段树
维护按后序遍历树时比当前点值大的数量
但是遍历到一个点时,维护的数量可能包含了他的兄弟,祖先
所以求出每个点的答案之前,记录出值pre,在遍历子树,加入树状数组,再求出值ans[x]
ans[x]=ans[x]-pre
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Messi
{
int next,to;
} edge[];
int c[];
int n,num,head[],a[],id[],ans[],p[];
void add(int u,int v)
{
num++;
edge[num].next=head[u];
head[u]=num;
edge[num].to=v;
}
int binary(int x)
{
int l=,r=n,mid;
while(l<=r)
{
mid=(l+r)>>;
if(a[mid]==x)return mid;
if(a[mid]>x)r=mid-;
else l=mid+;
}
return -;
}
int getsum(int rt,int l,int r,int L,int R)
{
if (l>=L&&r<=R)
{
return c[rt];
}
int mid=(l+r)/;
int x=;
if (L<=mid)
x+=getsum(rt*,l,mid,L,R);
if (R>mid)
x+=getsum(rt*+,mid+,r,L,R);
return x;
}
void update(int rt,int l,int r,int k)
{
if (l==r)
{
c[rt]=;
return;
}
int mid=(l+r)/;
if (k<=mid)
update(rt*,l,mid,k);
else update(rt*+,mid+,r,k);
c[rt]=c[rt*]+c[rt*+];
}
void dfs(int x)
{int i;
int tmp=getsum(,,n,id[x]+,n);
for (i=head[x];i;i=edge[i].next)
{
dfs(edge[i].to);
}
ans[x]=getsum(,,n,id[x]+,n)-tmp;
update(,,n,id[x]);
}
int main()
{int i,x;
cin>>n;
for (i=; i<=n; i++)
{
scanf("%d",&p[i]);
a[i]=p[i];
}
sort(a+,a+n+);
for (i=; i<=n; i++)
id[i]=binary(p[i]);
for (i=; i<=n; i++)
{
scanf("%d",&x);
add(x,i);
}
dfs();
for (i=;i<=n;i++)
printf("%d\n",ans[i]);
}