题意
给定一棵树,以及 \(m\) 条路径。
让你选出最少的点,使得对于每一条路径,都有一个点距离链上的点离端点更近。
Sol
考虑将每一条路径分为直链和曲链考虑。
注意到所有的曲链最多对答案有 \(1\) 的贡献。
考虑直链的情况。
注意到一个很显然的东西。
对于一个选择的点,如果她的上方不是端点,那她就可以一直向上移动,答案不会变劣。
考虑对于直链做树形dp。
设 \(f_i\) 表示在 \(i\) 子树内满足所有直链的贡献的最小答案。
对于平凡的情况,\(f_u = \sum f_v\)。
如果当前节点的父亲是一个端点,考虑这样一种情况:
如果当前有儿子有 \(dp\) 值,那么除了当前儿子以外,都不需要有贡献。
所以 \(f_u = max(f_v + 1, f_u)\)。
Code
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <vector>
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;
#endif
int read() {
int p = 0, flg = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') flg = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
p = p * 10 + c - '0';
c = getchar();
}
return p * flg;
}
void write(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
const int N = 3e5 + 5, M = 6e5 + 5;
namespace G {
array <int, N> fir;
array <int, M> nex, to;
int cnt;
void add(int x, int y) {
cnt++;
nex[cnt] = fir[x];
to[cnt] = y;
fir[x] = cnt;
}
}
namespace Hpt {
using G::fir; using G::nex; using G::to;
array <int, N> fa, dep, son, siz;
void dfs1(int x) {
siz[x] = 1;
for (int i = fir[x]; i; i = nex[i]) {
if (to[i] == fa[x]) continue;
fa[to[i]] = x;
dep[to[i]] = dep[x] + 1;
dfs1(to[i]);
siz[x] += siz[to[i]];
if (siz[to[i]] > siz[son[x]]) son[x] = to[i];
}
}
array <int, N> dfn, idx, top;
int cnt;
void dfs2(int x, int Mgn) {
cnt++;
dfn[x] = cnt;
idx[cnt] = x;
top[x] = Mgn;
if (son[x]) dfs2(son[x], Mgn);
for (int i = fir[x]; i; i = nex[i]) {
if (to[i] == fa[x] || to[i] == son[x]) continue;
dfs2(to[i], to[i]);
}
}
int lca(int x, int y) {
while (top[fa[y]] != top[x] && y)
y = top[fa[y]];
if (dep[son[x]] < dep[y]) return son[x];
else return y;
}
}
array <vector <int>, N> isl;
array <int, N> f;
void dfs(int x) {
for (int i = G::fir[x]; i; i = G::nex[i]) {
if (G::to[i] == Hpt::fa[x]) continue;
dfs(G::to[i]), f[x] += f[G::to[i]];
}
if (isl[x].size()) f[x] = max(f[x], f[isl[x][0]] + 1);
}
vector <int> __;
int _;
int read_() { return __[_++]; }
int main() {
int n = read(), m = read();
for (int i = 2; i <= n; i++) {
int x = read();
G::add(i, x), G::add(x, i);
}
Hpt::dfs1(1), Hpt::dfs2(1, 0);
for (int i = 1; i <= m; i++) {
int x = read(), y = read();
if (Hpt::dep[x] > Hpt::dep[y]) swap(x, y);
int z = Hpt::lca(x, y);
// write(z), puts("");
if (Hpt::fa[y] == x) return puts("-1"), 0;
if (Hpt::fa[z] != x) __.push_back(x), __.push_back(y);
else isl[z].push_back(y);
}
dfs(1); int ans = f[1];
for (int i = 1; i <= __.size() / 2; i++) {
int x = read_(), y = read_();
ans = max(ans, f[x] + f[y] + 1);
}
write(ans), puts("");
return 0;
}
标签:fir,cnt,int,Squid,son,CF1610H,fa,Game,nex
From: https://www.cnblogs.com/cxqghzj/p/17897572.html