「Luogu P4149」「IOI2011」Race

Posted -wallace-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「Luogu P4149」「IOI2011」Race相关的知识,希望对你有一定的参考价值。

Description

给一棵 (n) 个点的树,每条边有权。求一条简单路径,权值和等于 (k),且边的数量最小。

Hint

  • (1le nle 2 imes 10^5)
  • (1le k, ext{边权}le 10^6)

Solution

还行的一道点分治题。

(k) 的范围不是很大,所以开一个大小为 (10^6) 的桶,( ext{rec}_i) 表示权值和为 (i) 的路径的最小边数。

更具体地,假如当前重心(根)结点的所有子树的根分别为:(x_1,x_2,cdots,x_k),而现在处理好了 (x_1,x_2,cdots,x_{k-1}) 这几颗子树之间产生的答案,那么 ( ext{rec}) 就保存了 (x_1,x_2,cdots,x_{k-1}) 这几颗子树中所有结点到根路径的信息。

对于子树 (x_k) 中某一条路径,长度和权值分别为 ((L, V)),那么这样更新答案:( ext{ans}leftarrow min( ext{ans}, ext{rec}_{k-V}+L))

在处理完一颗子树之后,对于该子树中所有的路径,对 (rec) 这样更新:( ext{rec}_V leftarrow min( ext{rec}_V, L))

于是……这道题就切掉了 QwQ!

  • 时间复杂度:(O(nlog n))
  • 空间复杂度:(O(n+k))

Code

#include <cstdio>
#include <cstring>
#include <utility>
#include <vector>

using namespace std;
const int N = 2e5 + 5;
const int K = 1e6 + 5;

int n, k, ans;
struct edge { int to, val; };
vector<edge> G[N];

int root;
int maxp[N], size[N];
bool centr[N];
int getSize(int x, int f) {
	size[x] = 1;
	for (auto y : G[x])
		if (y.to != f && !centr[y.to])
			size[x] += getSize(y.to, x);
	return size[x];
}
void getCentr(int x, int f, int t) {
	maxp[x] = 0;
	for (auto y : G[x]) {
		if (y.to == f || centr[y.to]) continue;
		getCentr(y.to, x, t);
		maxp[x] = max(maxp[x], size[y.to]);
	}
	maxp[x] = max(maxp[x], t - size[x]);
	if (maxp[x] < maxp[root]) root = x;
}

int tot;
pair<int, int> path[N];
vector<pair<int, int> > all;
int rec[K];
void getPaths(int x, int f, int l, int v) {
	if (v > k) return;
	path[++tot] = {l, v};
	for (auto y : G[x])
		if (y.to != f && !centr[y.to])
			getPaths(y.to, x, l + 1, v + y.val);
}

void solve(int x) {
	getSize(x, 0);
	maxp[root = 0] = N;
	getCentr(x, 0, size[x]);
	int s = root;
	centr[s] = true;
	
	for (auto y : G[s])
		if (!centr[y.to]) solve(y.to);
	
	rec[0] = 0;
	for (auto y : G[s]) {
		if (centr[y.to]) continue;
		tot = 0, getPaths(y.to, x, 1, y.val);
		for (register int i = 1; i <= tot; i++)
			ans = min(ans, rec[k - path[i].second] + path[i].first);
		for (register int i = 1; i <= tot; i++) {
			all.push_back(path[i]);
			rec[path[i].second] = min(path[i].first, rec[path[i].second]);
		}
	}
	
	for (auto i : all)
		rec[i.second] = 0x3f3f3f3f;
	all.clear();
	centr[s] = false;
}

signed main() {
	scanf("%d%d", &n, &k);
	for (register int i = 1; i < n; i++) {
		int s, t, v;
		scanf("%d%d%d", &s, &t, &v);
		s++, t++;
		G[s].push_back(edge{t, v});
		G[t].push_back(edge{s, v});
	}
	
	memset(rec, 0x3f, sizeof rec);
	ans = N, solve(1);
	printf("%d
", ans == N ? -1 : ans);
	return 0;
}

以上是关于「Luogu P4149」「IOI2011」Race的主要内容,如果未能解决你的问题,请参考以下文章

P4149 [IOI2011]Race

P4149 [IOI2011]Race

P4149 [IOI2011]Race

P4149 [IOI2011]Race 点分治

P4149 [IOI2011]Race

Luogu4149 [IOI2011]Race