Counting Offspring--dfs序+树状数组

题目链接:https://cn.vjudge.net/problem/HDU-3887

题目大意

有一棵以p为根的树,找出每个点的子树中,编号比其小的数量。例如,9号节点的子树有2,8,10,11,比9小的有两个,那么输出2。

分析

先dfs序,把每个点及其子树放在一个连续的区间内。接下来,就是要求比每个节点编号小的数量了。我们可以从1号节点开始,即从最小的开始,先查询dfs后对应区间内有多少个,再更新,更新时放入的是in[i],不能放i,因为i不一定在i+1对应的区间内。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 100010;
int n, p, cnt, tot;
int in[N], out[N], head[2*N], c[N];
struct Edge{
	int to, nxt;
}edge[2*N];
int lowbit(int x)
{
	return x & (-x);
}
void updata(int x)
{
	while(x < N)
	{
		c[x] += 1;
		x += lowbit(x);
	}
}
int query(int x)
{
	int sum = 0;
	while(x)
	{
		sum += c[x];
		x -= lowbit(x);
	}
	return sum;
}
void add(int a, int b)
{
	edge[cnt].to = b;
	edge[cnt].nxt = head[a];
	head[a] = cnt++;
}
void dfs(int x, int pre)
{
	in[x] = ++tot;
	for(int i = head[x]; i != -1; i = edge[i].nxt)
	{
		int j = edge[i].to;
		if(j == pre) continue;
		dfs(j, x);
	}
	out[x] = tot;
}
int main()
{
	while(~scanf("%d %d", &n, &p))
	{
		if(n == 0 && p == 0) break;
		cnt = tot = 0;
		memset(head, -1, sizeof head);
		memset(c, 0, sizeof c);
		for(int i = 1; i < n; i++)
		{
			int a, b;
			scanf("%d %d", &a, &b);
			add(a, b);
			add(b, a);
		}
		dfs(p, 0);
		for(int i = 1; i <= n; i++)
		{
			printf("%d%s", query(out[i]) - query(in[i] - 1), i == n ? "\n" : " ");
			updata(in[i]);
		}
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值