1、嘛,在学姐的帮助下,按照求“以一个结点为根的子树中比它编号大的结点数”这个题意,用Fenwick树做出来了。
2、其实比赛的时候我有想到过用线段树或者树状数组,但是我不知道该维护什么值。题目给出的是一棵树,树状数组(或者线段树)也是一棵树,如何对应?难道是让根节点与线段树中最长的那个区间对应吗?感觉无从下手了。
3、现在明白了,维护的是“当前已访问过的编号小于等于x的结点数”,也就是说sum【x】表示当前已访问过的编号小于等于x的结点数。对于一棵子树,访问这棵子树后和访问前的“大于根结点的结点数”之差,也就是这棵子树里面大于根节点的结点数。这个思路非常巧妙,学习了。
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
vector<int> g[50010];
int c[50010],ans[50010],n;
int lowbit(int x){
return x&-x;
}
int sum(int x){
int ret=0;
while(x>0){
ret+=c[x];x-=lowbit(x);
}
return ret;
}
void add(int x,int d){
while(x<=n){
c[x]+=d;x+=lowbit(x);
}
}
void dfs(int x){
ans[x]=sum(n)-sum(x);
add(x,1);
for(int i=0;i<g[x].size();i++)
dfs(g[x][i]);
ans[x]=sum(n)-sum(x)-ans[x];
return;
}
int main(){
int T,temp,kase=1;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=1;i<=n;i++)
g[i].clear();
for(int i=2;i<=n;i++){
scanf("%d",&temp);
g[temp].push_back(i);
}
memset(c,0,sizeof(c));
dfs(1);
printf("Case #%d:",kase++);
for(int i=1;i<=n;i++)
printf(" %d",ans[i]);
printf("\n");
}
return 0;
}