标签:lan i++ ext cond const memset can std tar
给一棵 \(n\) 个点的树,每条边有权。求一条简单路径,权值和等于 \(k\),且边的数量最小。
还行的一道点分治题。
\(k\) 的范围不是很大,所以开一个大小为 \(10^6\) 的桶,\(\text{rec}_i\) 表示权值和为 \(i\) 的路径的最小边数。
更具体地,假如当前重心(根)结点的所有子树的根分别为:\(x_1,x_2,\cdots,x_k\),而现在处理好了 \(x_1,x_2,\cdots,x_{k-1}\) 这几颗子树之间产生的答案,那么 \(\text{rec}\) 就保存了 \(x_1,x_2,\cdots,x_{k-1}\) 这几颗子树中所有结点到根路径的信息。
对于子树 \(x_k\) 中某一条路径,长度和权值分别为 \((L, V)\),那么这样更新答案:\(\text{ans}\leftarrow \min(\text{ans}, \text{rec}_{k-V}+L)\)。
在处理完一颗子树之后,对于该子树中所有的路径,对 \(rec\) 这样更新:\(\text{rec}_V \leftarrow \min(\text{rec}_V, L)\)。
于是……这道题就切掉了 QwQ!
#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\n", ans == N ? -1 : ans);
return 0;
}
标签:lan i++ ext cond const memset can std tar
原文地址:https://www.cnblogs.com/-Wallace-/p/12853760.html