吉林大学ACM集训队选拔赛(重现赛)I-Firework (最短路)

链接:https://ac.nowcoder.com/acm/contest/5944/I
来源:牛客网
 

题目描述

Alice and Bob get a strange firework accidentally, and they never know how to play it, so they come to you for help.

The firework consists of n nodes and n-1 fuses connecting pairs of nodes. The whole firework forms an undirected tree. At the time 0, several nodes are ignited simultaneously. After that, the fire begins to spread through the fuses to all directions from those nodes which has been ignited. When the fire reaches another node that haven't been ignited before, it will ignite the node and keep spreading.

Fire has a specific speed. If the fuse has the length L, it needs 2L seconds to conduct the fire. Then the question comes: how long it will take to burn up the firework? We consider that the firework is burned up if and only if all the fuses are burned up.

输入描述:

The first line contains two integers n, m (1≤n,m≤105)(1\leq n,m\leq10^5)(1≤n,m≤105) -- the number of nodes of the firework and the number of nodes which are ignited initially.

This is followed by n-1 lines with fuse descriptions. Each fuse is given by three integers u, v and w (1≤u,v≤n,1≤w≤109)(1\leq u, v\leq n, 1\leq w \leq 10^9)(1≤u,v≤n,1≤w≤109), meaning that there is a fuse between node u and v with the length w.

The next line contains m distinct integers describing the ignited nodes' numbers.

输出描述:

Only one line with a single number T --  the time it takes to burn up the firework.

示例1

输入

复制3 2 1 2 1 2 3 2 1 3

3 2
1 2 1
2 3 2
1 3

输出

复制3

3

说明

For the first example, the fire reaches node 2 from the fuse (1,2) in 2 seconds. But the fuse (2,3) is still burning, the final answer is 3 seconds.

示例2

输入

复制5 2 1 2 5 2 3 1 2 4 2 4 5 1 1 4

5 2
1 2 5
2 3 1
2 4 2
4 5 1
1 4

输出

复制7

7

题目大意:

一棵N(1e5)个点的带边权树,你要在K个点同时点火,火每2单位时间可以烧一单位长度,问你把所有的边烧完需要多长时间。

解法:

不难看出每条边有且仅有两个着火点靠近,所以求出每条边的两端着火时间,将K个点加进队列,跑最短路的过程中记录着火时间,最后判断一下该边是一头烧完还是两头一起烧完,取所有边烧完时间的最大值。

Accepted code

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 1e5 + 100;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
inline ll dpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % Mod; b >>= 1; t = (t*t) % Mod; }return r; }
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t); b >>= 1; t = (t*t); }return r; }

struct node
{
	int id; ll w;
	bool operator < (const node &oth) const {
		return w > oth.w;
	}
};
vector <pir> G[N << 1];
vector <ll> vec[N];
ll dis[N], val[N];
bool vis[N];
int n, k;

void dijkstra() {
	priority_queue <node> q;
	MEM(dis, LINF);
	for (int i = 0; i < k; i++) {
		int t;
		sc("%d", &t);
		dis[t] = 0;
		q.push({ t, 0ll });   // 加入队列
	}
	while (!q.empty()) {
		node now = q.top();
		q.pop();
		int u = now.id;
		if (vis[u])
			continue;
		vis[u] = true;

		for (auto it : G[u]) {
			int v = it.second, id = it.first;
			vec[id].push_back(dis[u]);           // 着火时间点
			if (dis[v] > dis[u] + val[id]) {
				dis[v] = dis[u] + val[id];
				q.push({ v, dis[v] });
			}
		}
	}
}

int main()
{
	cin >> n >> k;
	for (int i = 1; i < n; i++) {
		int u, v;
		sc("%d %d %lld", &u, &v, &val[i]);
		G[u].push_back({ i, v });
		G[v].push_back({ i, u });
	}
	dijkstra();

	ll ans = 0;
	for (int i = 1; i < n; i++) {
		ll l = vec[i][0], r = vec[i][1];
		ll w = val[i];
		if (l > r)
			swap(l, r);        // 两端着火时间
		if (l + w <= r)           // 一头烧完
			Max(ans, 2ll * (l + w));
		else                      // 两头一起烧完
			Max(ans, 2 * r + (l + w - r));
	}
	printf("%lld\n", ans);
	return 0;  // 改数组大小!!!用pair记得改宏定义!!!
}

猜你喜欢

转载自blog.csdn.net/weixin_43851525/article/details/107042817