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;
}

posted on 2021-11-02 20:00  gryzy  阅读(24)  评论(0编辑  收藏  举报

导航