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