HDU 4366 树上分块

Successor

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 4637    Accepted Submission(s): 1161


Problem Description
Sean owns a company and he is the BOSS.The other Staff has one Superior.every staff has a loyalty and ability.Some times Sean will fire one staff.Then one of the fired man’s Subordinates will replace him whose ability is higher than him and has the highest loyalty for company.Sean want to know who will replace the fired man.
 

Input
In the first line a number T indicate the number of test cases. Then for each case the first line contain 2 numbers n,m (2<=n,m<=50000),indicate the company has n person include Sean ,m is the times of Sean’s query.Staffs are numbered from 1 to n-1,Sean’s number is 0.Follow n-1 lines,the i-th(1<=i<=n-1) line contains 3 integers a,b,c(0<=a<=n-1,0<=b,c<=1000000),indicate the i-th staff’s superior Serial number,i-th staff’s loyalty and ability.Every staff ‘s Serial number is bigger than his superior,Each staff has different loyalty.then follows m lines of queries.Each line only a number indicate the Serial number of whom should be fired.
 

Output
For every query print a number:the Serial number of whom would replace the losing job man,If there has no one to replace him,print -1.
 

Sample Input
  
  
1 3 2 0 100 99 1 101 100 1 2
 

Sample Output
  
  
2

-1

题意:n个职员的父子关系组成一棵树,除了BOSS的每个职员都有忠诚度和能力值且忠诚度互不相同,查询m次,每次查询某个节点的子孙中能力值比它大且忠诚度最高的节点。

对于每个节点只需要查询它的子孙,因此如果把这棵树转化成一个序列的话,相当于进行m次区间查询,可以用分块查询。

但是查询忠诚度最大的前提是能力值足够大,这样是无法O(1)查询每个块的,首先对于每个完整块以忠诚度排序,再开个数组记录后缀最大值,s[i]表示能力值大于等于该点的最大忠诚度,这样就可以二分查找了。

剩余非完整块暴力查询。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<math.h>
using namespace std;
const int maxm = 50005;
int cnt, magic;
struct H
{
	int loy, ab;
	bool operator<(const H &pp)const
	{
		return pp.ab > ab;
	}
}a[maxm], f[maxm], p[maxm];
vector<int>v[maxm];
int id[1000005], s[maxm], L[maxm], R[maxm];
void dfs(int k)
{
	L[k] = cnt;
	p[cnt].loy = f[k].loy, p[cnt].ab = f[k].ab;
	for (int i = 0;i < v[k].size();i++)
	{
		cnt++;
		f[cnt] = p[cnt] = a[v[k][i]];
		dfs(v[k][i]);
	}
	R[k] = cnt;
}
int query(int l, int r, int val)
{
	if (p[r].ab <= val) return -1;
	if (p[l].ab > val) return s[l];
	while (l <= r)
	{
		int mid = (l + r) / 2;
		if (p[mid].ab > val) r = mid - 1;
		else l = mid + 1;
	}
	return s[l];
}
int solve(int x)
{
	int val = a[x].ab, s = L[x], end = R[x];
	int ans = -1;
	for (int i = s + 1;i <= end;)
	{
		if (i%magic == 0 && i + magic <= end)
		{
			ans = max(ans, query(i, i + magic - 1, val));
			i += magic;
		}
		else
		{
			if (f[i].ab > val&&ans < f[i].loy)	ans = f[i].loy;
			i++;
		}
	}
	if (ans == -1) return -1;
	return id[ans];
}
int main()
{
	int n, i, j, k, sum, t, m, u;
	scanf("%d", &t);
	while (t--)
	{
		memset(s, -1, sizeof(s));
		scanf("%d%d", &n, &m);cnt = 0;
		for (i = 0;i < n;i++) v[i].clear();
		for (i = 1;i < n;i++)
		{
			scanf("%d%d%d", &u, &a[i].loy, &a[i].ab);
			id[a[i].loy] = i, v[u].push_back(i);
		}
		dfs(0);
		magic = sqrt(n*1.0);
		for (i = 0;i < n;i += magic)
		{
			j = i + magic;
			if (j > n) break;
			sort(p + i, p + j);
			s[j - 1] = p[j - 1].loy;
			for (k = j - 2;k >= i;k--)
			{
				if (p[k].loy < s[k + 1]) s[k] = s[k + 1];
				else s[k] = p[k].loy;
			}
		}
		while (m--)
		{
			scanf("%d", &u);
			printf("%d\n", solve(u));
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值