HDU 3887 Counting Offspring

35 篇文章 0 订阅
16 篇文章 0 订阅
Font Size:  

Problem Description

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

dfs序+树状数组+数组模拟链表来存储树

# include<stdio.h>
# include<math.h>
# include<string.h>
#pragma comment(linker, "/STACK:1024000000,1024000000")  //防爆栈

struct abc
{
    int next,just;
};
abc f[300000];
int n, e, root;
int frist[100005], c[100005], d[100005];

int add(int x, int y)
{
    f[e].just = y; f[e].next = frist[x]; frist[x] = e++;
    f[e].just = x; f[e].next = frist[y]; frist[y] = e++;
    return 0;
}

int lowb(int t){ return t&(-t); }

int fadd(int x)
{
    while (x <= n) { d[x]++; x += lowb(x); }
    return 0;
}

int sum(int x)
{
    if (x <= 0) return 0;
    return d[x] + sum(x - lowb(x));
}

int ss(int x, int fa)
{
    int a = sum(x);
    int k = frist[x];
    while (k > 0)
    {
        if (f[k].just != fa)
        {
            fadd(f[k].just);
            ss(f[k].just, x);
        }
        k = f[k].next;
    }
    c[x] = sum(x) - a;
    return 0;
}

int main()
{
    while (scanf("%d%d", &n, &root) != EOF&&n+root)
    {
        memset(f,0,sizeof(f));
        memset(frist, 0, sizeof(frist));
        memset(d, 0, sizeof(d));
        e = 1;
        for (int i = 1; i < n; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            add(a, b);
        }
        ss(root,root);
        printf("%d", c[1]);
        for (int i =2; i <= n; i++) printf(" %d", c[i]);
        printf("\n");
    }
    return 0;
}

hdu上这个已经过不了了,只能手动模拟栈。

# include<stdio.h>
# include<math.h>
# include<string.h> 
# include<stack>
# include<algorithm>
using namespace std;
stack<int> p;

struct wrz
{
	int next, just;
};
wrz f[300000];
int n, e, root;
int frist[100005], c[100005], d[100005], u[100005];

int add(int x, int y)
{
	f[e].just = y; f[e].next = frist[x]; frist[x] = e++;
	f[e].just = x; f[e].next = frist[y]; frist[y] = e++;
	return 0;
}

int lowb(int t){ return t&(-t); }

int fadd(int x)
{
	while (x <= n) { d[x]++; x += lowb(x); }
	return 0;
}

int sum(int x)
{
	if (x <= 0) return 0;
	return d[x] + sum(x - lowb(x));
}

int ss(int x)
{
	p.push(x);	u[x] = 1;
	while (!p.empty())
	{
		begin:int x = p.top();
		if (c[x] == 0) {
			fadd(x);
			c[x] = sum(x);
		}
		int k = frist[p.top()];
		while (k > 0)
		{
			if (u[f[k].just] == 0)
			{
				u[f[k].just] = 1;
				p.push(f[k].just);
				goto begin;
			}
			k = f[k].next;
		}
		c[x] = sum(x) - c[x];
		p.pop();
	}
	return 0;
}

int main()
{
	while (~scanf("%d%d", &n, &root), n + root)
	{
		memset(f, 0, sizeof(f));
		memset(frist, 0, sizeof(frist));
		memset(d, 0, sizeof(d));
		memset(u, 0, sizeof(u));
		memset(c, 0, sizeof(c));
		e = 1;
		for (int i = 1; i < n; i++)
		{
			int a, b;
			scanf("%d%d", &a, &b);
			add(a, b);
		}
		ss(root);
		printf("%d", c[1]);
		for (int i = 2; i <= n; i++) printf(" %d", c[i]);
		printf("\n");
	}
	return 0;
}
上面这个是用了goto的,下面的是普通的。
# include<stdio.h>
# include<math.h>
# include<string.h> 
# include<stack>
# include<algorithm>
using namespace std;
stack<int> p;

struct wrz
{
	int next, just;
};
wrz f[300000];
int n, e, root;
int frist[100005], c[100005], d[100005], u[100005];

int add(int x, int y)
{
	f[e].just = y; f[e].next = frist[x]; frist[x] = e++;
	f[e].just = x; f[e].next = frist[y]; frist[y] = e++;
	return 0;
}

int lowb(int t){ return t&(-t); }

int fadd(int x)
{
	while (x <= n) { d[x]++; x += lowb(x); }
	return 0;
}

int sum(int x)
{
	if (x <= 0) return 0;
	return d[x] + sum(x - lowb(x));
}

int ss(int x)
{
	p.push(x);	u[x] = 1;
	while (!p.empty())
	{
		int x = p.top();
		if (c[x] == 0) { fadd(x); c[x] = sum(x); }
		for (int k = frist[x]; k; k = f[k].next)
			if (u[f[k].just] == 0)
			{
				u[f[k].just] = 1;
				p.push(f[k].just);
			}
		if (p.top() == x)
		{
			c[x] = sum(x) - c[x];
			p.pop();
		}
	}
	return 0;
}

int main()
{
	while (~scanf("%d%d", &n, &root), n + root)
	{
		memset(f, 0, sizeof(f));
		memset(frist, 0, sizeof(frist));
		memset(d, 0, sizeof(d));
		memset(u, 0, sizeof(u));
		memset(c, 0, sizeof(c));
		e = 1;
		for (int i = 1; i < n; i++)
		{
			int a, b;
			scanf("%d%d", &a, &b);
			add(a, b);
		}
		ss(root);
		printf("%d", c[1]);
		for (int i = 2; i <= n; i++) printf(" %d", c[i]);
		printf("\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值