zoj3516 线段树

Tree of Three

Time Limit: 2 Seconds Memory Limit: 65536 KB

Now we have a tree and some queries to deal with. Every node in the tree has a value on it. For one node A, we want to know the largest three values in all the nodes of the subtree whose root is node A. Node 0 is root of the tree, except it, all other nodes have a parent node.

Input

There are several test cases. Each test case begins with a line contains one integer n(1 ≤ n ≤ 10000), which indicates the number of the node in the tree. The second line contains one integer v[0], the value on the root. Then for the following n - 1 lines(from the 3rd line to the (n + 1)th line), let i + 2 be the line number, then line i + 2 contains two integers parent and v[i], here parent is node i's parent node, v[i] is the value on node i. Here 0 ≤ v[i] ≤ 1000000. Then the next line contains an integer m(1 ≤ m ≤ 10000), which indicates the number of queries. Following m lines, each line contains one integer q, 0 ≤ q < n, it meas a query on node q.

Output

For each test case, output m lines, each line contains one or three integers. If the query asked for a node that has less than three nodes in the subtree, output a "-1"; otherwise, output the largest three values in the subtree, from larger to smaller.

Sample Input
5
1
0 10
0 5
2 7
2 8
5
0
1
2
3
4
Sample Output
10 8 7
-1
8 7 5
-1
-1


题意:给一颗树,每个结点都有一个权值,问某一点及其子树中,最大的三个数

思路:其实根已经确定了,直接深搜就行了,其实连建树都不用。而我刚看到的时候一直想着怎么建树,想着想着就写成线段树了。因为一开始就想到zoj3686,但是一直想不起来当时是怎么建树的,然后找了一下源代码,下面的dfs代码,就是把当前结点放在左端,然后通过递归回来的最后一个结点放在右端。然后判断一个结点是否满足三个数以上只须判断他的左右间距是否大于3,然后查找就是线段树查找了

void add(int s,int e){
	E[ind].e=e;
	E[ind].next=head[s];
	head[s]=ind++;
}
void dfs(int s){
	l[s]=++p;
	for(int now=head[s];now!=-1;now=E[now].next){
		dfs(E[now].e);
	}
	r[s]=p;
}


#include<cstdio>
#include<cstring>
#include<stdlib.h>
using namespace std;
#define SIZE 10005
#define lson rt<<1
#define rson rt<<1|1
int head[SIZE],l[SIZE],r[SIZE],w[SIZE],ind,p,tp;
int val[SIZE],cou[SIZE];
struct tree{
	int l,r,sum;
	int num[7];
}T[SIZE<<2];
struct edge{
	int e,next;
}E[SIZE];
int cmp(const void *a,const void *b){
	return *(int *)b-*(int *)a;
}
void add(int s,int e){
	E[ind].e=e;
	E[ind].next=head[s];
	head[s]=ind++;
}
void dfs(int s){
	l[s]=++p;
	for(int now=head[s];now!=-1;now=E[now].next){
		dfs(E[now].e);
	}
	r[s]=p;
}
void pushup(int rt){
	int sum=T[lson].sum+T[rson].sum;
	T[rt].sum=(sum>6?6:sum);
	int top=0;
	for(int i=0;i<T[lson].sum&&i<3;i++)
		T[rt].num[top++]=T[lson].num[i];
	for(int i=0;i<T[lson].sum&&i<3;i++)
		T[rt].num[top++]=T[rson].num[i];
	qsort(T[rt].num,top,sizeof(T[rt].num[0]),cmp);
}
void built(int l,int r,int rt){
	T[rt].l=l;
	T[rt].r=r;
	T[rt].sum=0;
	if(l==r) {
		T[rt].sum=1;
		T[rt].num[0]=val[l];
		return;
	}
	int mid=(l+r)>>1;
	built(l,mid,lson);
	built(mid+1,r,rson);
	pushup(rt);
}
void query(int l,int r,int rt){
	if(l<=T[rt].l&&T[rt].r<=r){
		for(int i=0;i<T[rt].sum&&i<3;i++)
			cou[tp++]=T[rt].num[i];
		return;
	}
	int mid=(T[rt].l+T[rt].r)>>1;
	if(l<=mid)
		query(l,r,lson);
	if(r>mid)
		query(l,r,rson);
}
int main(void){
	int n,pre;
	int m;
	while(~scanf("%d",&n)){
		memset(head,-1,sizeof(head));
		ind=p=0;
		scanf("%d",&w[0]);
		for(int i=1;i<n;i++){
			scanf("%d%d",&pre,&w[i]);
			add(pre,i);
		}
		dfs(0);
		for(int i=0;i<n;i++)
			val[l[i]]=w[i];		
		built(l[0],r[0],1);
		scanf("%d",&m);
		while(m--){
			scanf("%d",&pre);
			if(r[pre]-l[pre]+1<3){
				printf("-1\n");
				continue;
			}
			tp=0;
			query(l[pre],r[pre],1);
			qsort(cou,tp,sizeof(cou[0]),cmp);
			printf("%d %d %d\n",cou[0],cou[1],cou[2]);
			
		}
	}
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值