Counting Offspring(hdu 3887dfs+树状数组)

You are given a tree, it’s root is p, and the node is numbered from 1 to n. Now define f(i) as the number of nodes whose number is less than i in all the succeeding nodes of node i. Now we need to calculate f(i) for any possible i.
Input
Multiple cases (no more than 10), for each case:
The first line contains two integers n (0<n<=10^5) and p, representing this tree has n nodes, its root is p.
Following n-1 lines, each line has two integers, representing an edge in this tree.
The input terminates with two zeros.
Output
For each test case, output n integer in one line representing f(1), f(2) … f(n), separated by a space.
Sample Input
15 7
7 10
7 1
7 9
7 3
7 4
10 14
14 2
14 13
9 11
9 6
6 5
6 8
3 15
3 12
0 0
Sample Output
0 0 0 0 0 1 6 0 3 1 0 0 0 2 0
f(i) 代表着i的子树中节点编号比i小的节点个数。
对于树上操作来说,dfs是少不了的,那么我们怎么在dfs的过程中去找到这个f(i)呢?显然可以用树状数组来实现这个功能。在进入一个子树之前,我们可以统计在这之前该节点之前的节点有多少已经被统计了,出了这个子树以后我们在统计一遍,做个差。这样就是它的子树中节点编号小于该节点的数目。
代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#define ll long long
using namespace std;

const int maxx=1e5+100;
int head[maxx*2],sum[maxx],c[maxx*2];
int vis[maxx];
struct edge{
	int to;
	int next;
}e[maxx*2];
int n,root,tot,sign;

void init()
{
	tot=sign=0;
	memset(head,-1,sizeof(head));
	memset(sum,0,sizeof(sum));
}
void addedge(int u,int v)
{
	e[tot].to=v,e[tot].next=head[u],head[u]=tot++;
}
int lowbit(int x){return x&-x;}
void add(int cur,int w)
{
	while(cur<2*maxx)
	{
		c[cur]+=w;
		cur+=lowbit(cur);
	}
}
int query(int cur)
{
	int ans=0;
	while(cur)
	{
		ans+=c[cur];
		cur-=lowbit(cur);
	}
	return ans;
}
void dfs(int u,int f)
{
	sum[u]=query(u-1);
	for(int i=head[u];i!=-1;i=e[i].next)
	{
		int to=e[i].to;
		if(to==f) continue;
		add(to,1);
		dfs(to,u);
	}
	sum[u]=query(u-1)-sum[u];
}
int main()
{
	while(scanf("%d%d",&n,&root),n||root)
	{
		init();
		int x,y;
		for(int i=1;i<n;i++)
		{
			scanf("%d%d",&x,&y);
			addedge(x,y);
			addedge(y,x);
		}
		dfs(root,0);
		for(int i=1;i<=n;i++) printf("%d%s",sum[i],i==n?"\n":" ");
	}
}

努力加油a啊,(o)/~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值