cogs2039
2039. 树的统计
输入文件:counttree.in 输出文件:counttree.out 简单对比
时间限制:1 s 内存限制:128 MiB
【题目描述】
关于树的统计问题有多种多样的版本,这里你需要解决一个比较简单的问题:对于一棵包含N个节点的有根树,将所有点从1到N编号后,对于每一个节点v,统计出以v为根的子树中有多少个点的编号比v小。
【输入格式】
输入第一行包含一个整数N,以下N行每行包含一个整数,其中第i行的整数表示编号为i的节点的父亲节点的编号,根的父亲节点编号为0。
【输出格式】
输出包含N行,其中第i行给出编号为i的节点的统计结果。
【样例输入】
3
2
3
0
【样例输出】
0 1 2
【来源】
20%的数据1<=n<=1000
100%的数据1<=n<=100000
本来是要写一个CDQ分治的,可是树状数组太好写了!
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n;
int sum[maxn];
void add(int pos,int x)
{
for(int i=pos;i<=n;i+=(-i)&i)sum[i]+=x;
}
int query(int pos)
{
int ret=0;
for(int i=pos;i;i-=(-i)&i)ret+=sum[i];
return ret;
}
struct edge
{
int u,v,nxt;
}e[maxn<<1];
int head[maxn],js;
void addage(int u,int v)
{
e[++js].u=u;e[js].v=v;
e[js].nxt=head[u];head[u]=js;
}
int l[maxn],r[maxn];
int root,cnt;
void dfs(int u,int fa)
{
l[u]=++cnt;
for(int i=head[u];i;i=e[i].nxt)
{
int v=e[i].v;
if(v==fa)continue;
dfs(v,u);
}
r[u]=cnt;
}
int main()
{
freopen("counttree.in","r",stdin);
freopen("counttree.out","w",stdout);
scanf("%d",&n);
for(int x,i=1;i<=n;++i)
{
scanf("%d",&x);
if(x==0)
{
root=i;continue;
}
addage(i,x);addage(x,i);
}
dfs(root,0);
for(int i=1;i<=n;++i)
{
printf("%d ",query(r[i])-query(l[i]-1));
add(l[i],1);
}
return 0;
}