背景:
今天的luogu打卡被数竞队拿去竞猜,亏了
2
y
u
a
n
2yuan
2yuan。
紧接着下午就有了丰山录取的消息。
题目传送门:
https://www.luogu.org/problemnew/show/P3605
题意:
求树上每一个点的子树中大于根的权值的个数。
思路:
树上逆序对的问题。
在
d
f
s
dfs
dfs时求出当前所有遍历过的点的数目(
t
o
t
tot
tot),再减去权值小于根的点的数目,得到权值大于根的点的数目,最后减去不在当前子树内的贡献(
d
i
f
f
e
r
e
n
t
different
different)即可。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lowbit(x) (x&(-x))
using namespace std;
int n,len=0,tot=0;
struct node1{int x,id;} d[200010];
struct node2{int x,y,next;} a[200010];
int last[200010],id[200010],c[200010],ans[200010];
void add(int x,int y)
{
for(int i=x;i<=n;i+=lowbit(i))
c[i]+=y;
}
int getsum(int x)
{
int sum=0;
for(int i=x;i>=1;i-=lowbit(i))
sum+=c[i];
return sum;
}
bool cmp(node1 x,node1 y)
{
return x.x<y.x;
}
void ins(int x,int y)
{
a[++len]=(node2){x,y,last[x]}; last[x]=len;
}
void dfs(int x,int fa)
{
add(id[x],1);
tot++;
int different=tot-getsum(id[x]-1);
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
dfs(y,x);
}
ans[x]=tot-getsum(id[x]-1)-different;
}
int main()
{
int x;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&d[i].x);
d[i].id=i;
}
sort(d+1,d+n+1,cmp);
for(int i=1;i<=n;i++)
id[d[i].id]=i;
for(int i=2;i<=n;i++)
{
scanf("%d",&x);
ins(i,x),ins(x,i);
}
dfs(1,0);
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
}