Gym - 101915G Robots(贪心)

The Robotics Olympiad teams were competing in a contest.

There was a tree drawn on the floor, consisting of n nodes and n - 1 edges. The nodes are numbered from 1 to n, and each edge has a weight. The tree is rooted at the first node. q teams are participating, and each team is given an integer xi. Their robot should start at node 1, and move in the following way until there are no valid moves left: From all the edges between the current node and it’s children, go through the edge with the maximum value less than xi. Note that the robot can’t move to the parent, only to children.

However, the teams weren’t able to program the robots to return to them after the contest, so they had to manually pick them up. Since the tree can be quite large, they need your help to determine where each robot ended it’s movement.

Input
The first line contains a single integer T, the number of test cases.

The first line of each test case contains two space-separated integers n and q. (1 ≤ n, q ≤ 105).

The following n - 1 lines contain 3 integers ui, vi, wi. This means that there is an edge connecting nodes ui and vi, with weight wi. (1 ≤ ui, vi ≤ n) (1 ≤ wi ≤ 109). It’s guaranteed that all wi are distinct.

The following line contains q integers xi. (1 ≤ xi ≤ 109).

Output
For each test case, print one line with a single number Si, the sum of numbers of nodes where each robot ends.

Example
Input
1
5 7
1 2 3
1 3 4
3 4 9
3 5 7
1 3 4 9 8 7 10
Output
21
Note
In the sample test case, the robots end in the following nodes: {1, 1, 2, 5, 5, 3, 4}.

Si = 1+1+2+5+5+3+4 = 21.

Large I/O files. Please consider using fast input/output methods.

题意:t组样例,n个点的树,m个机器人。n-1行描述树。
机器人们从1出发,每次都走比自己权值小的最大的边,求最后机器人们停下的那些点的和。

做法:对树进行dfs,把每个点相邻的边都按照边权进行从大到小排序,找到到达每个点一路上的最大边权,然后从最大边权可以到达的点开始回溯。
总而言之就是我不会的类型(。)
看代码吧还是。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<list>
#include<math.h>
#include<vector>
#include<stack>
#include<string>
#include<set>
#include<map>
#include<numeric>
#include<stdio.h>
#include<functional>
#include<time.h>
#pragma warning(disable:6031)

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 10;
const ll mode = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const double pi = 3.14159265358979323846264338327950;
template <class T> inline T min(T a, T b, T c) { return min(min(a, b), c); }
template <class T> inline T max(T a, T b, T c) { return max(max(a, b), c); }
template <class T> inline T min(T a, T b, T c, T d) { return min(min(a, b), min(c, d)); }
template <class T> inline T max(T a, T b, T c, T d) { return max(max(a, b), max(c, d)); }

int t, m, n;

struct E
{
	int from, to;
	ll weight;
	bool operator<(E x)const
	{
		return weight > x.weight;
	}
};
vector<E>e[maxn];
priority_queue<ll>q;
ll maxx[maxn];
ll ans;

void init()
{
	for (int i = 0; i < maxn; i++) e[i].clear(), maxx[i] = 0;
	while (!q.empty()) q.pop();
	ans = 0;
}

void dfs(int nx,int fa)//从nx开始,fa是上一个点
{
	if (q.empty() || q.top() <= maxx[nx]) return;//如果优先队列已经为空,或者剩下的机器人都已经不满足到达这个点的条件,退出。
	int size = e[nx].size();
	for (int i = 0; i < size; i++)//对nx这个点发出的边进行遍历
	{
		int to = e[nx][i].to;
		ll w = e[nx][i].weight;
		if (to != fa && !q.empty())//如果不是上一个点,并且优先队列里面还有东西
		{
			maxx[to] = max(maxx[nx], w);//更新到达这个点的最大边权
			if (q.top() > w) dfs(to, nx);//如果满足条件就继续深搜,直到遇见第一个不满足的为止
		}
	}
	if (q.empty())return;
	while (q.top() > maxx[nx])//把所有满足到达这个点条件的机器人pop出来
	{
		ans += nx;//这个点的编号就是nx
		q.pop();
		if (q.empty())return;
	}
}

int main()
{
	scanf("%d", &t);
	while (t--)
	{
		init();
		scanf("%d %d", &n, &m);
		for (int i = 1; i <= n - 1; i++)
		{
			E a;
			scanf("%d %d %lld", &a.from, &a.to, &a.weight);
			e[a.from].push_back(a);
			swap(a.from, a.to);
			e[a.from].push_back(a);
		}
		for (int i = 1; i <= m; i++)
		{
			ll k;
			scanf("%lld", &k);
			q.push(k);
		}
		for (int i = 1; i <= n; i++)
			sort(e[i].begin(), e[i].end());

		dfs(1,-1);

		printf("%lld\n", ans);
	}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值