「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的主要内容,如果未能解决你的问题,请参考以下文章