zoj3516和树相关

12 篇文章 0 订阅

 

 

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4381

Contest: ZOJ Monthly, July 2011

给你一棵树,10000个节点,每个节点有一个权值,告诉你各个节点的权值和父亲节点,然后10000个查询,查询以每个节点为根的子树的最大三个值,如果小于3个输出-1.

 

不想存儿子节点,所以存了每个节点的父亲节点,然后每次扫描一遍所有节点,将叶子节点往上送。。。注意一点,为了避免太多扫描,往上送的过程中如果某一个节点的父亲节点也没有儿子节点了,就直接将该节点也往上送了。。。(最后发现有种非常特殊的情况还是会达到3*10^7)

最好的解法还是用vector存儿子节点,然后一个dfs就可以了。。。。。对一棵树DFS可以肆意妄为了。。。

 

代码:

 

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<memory.h>
using namespace std;

const int N=10010;
int m, n;
struct node
{
	int parent;
	int sonnum, cnt, a[3];
	void init()
	{
		sonnum = 0;
		cnt = 1;
	}
} a[N];

int cmp(int a, int b)
{
	return a>b;
}

void fun(int i)
{
	int l, k, j = a[i].parent;
	int b[6], bn;
	bn = 0;
	for(k=0; k<a[i].cnt; k++)
		b[bn++] = a[i].a[k];
	for(k=0; k<a[j].cnt; k++)
		b[bn++] = a[j].a[k];
	sort(b, b+bn, cmp);
	if(bn<=3)
		a[j].cnt = bn;
	else
		a[j].cnt = 3;
	for(k=0; k<a[j].cnt; k++)
		a[j].a[k] = b[k];
	a[j].sonnum--;
}

int main()
{
	int i, j, k, cas1=1, flag;
	while(scanf("%d", &n)!=EOF)
	{
		for(i=0; i<n; i++)
			a[i].init();
		scanf("%d", &a[0].a[0]);
		for(i=1; i<n; i++)
		{
			scanf("%d%d", &a[i].parent, &a[i].a[0]);
			j = a[i].parent;
			a[j].sonnum++;
		}
		flag = 1;
		while(flag)
		{
			for(i=1; i<n; i++)
			{
				j = i;
				while(j!=0 && a[j].sonnum==0 && a[j].parent!=-1)
				{
					flag = 0;
					fun(j);
					k = j;
					j = a[j].parent;
					a[k].parent = -1;
				}
			}
			if(flag==0)
				flag = 1;
			else
				break;
		}

		//printf("Case #%d:\n", cas1++);
		scanf("%d", &m);
		while(m--)
		{
			scanf("%d", &i);
			if(a[i].cnt<3)
				printf("-1\n");
			else
				printf("%d %d %d\n", a[i].a[0], a[i].a[1], a[i].a[2]);
		}
	}

	return 0;
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值