CF1610H Squid Game

发布时间 2023-12-12 18:34:52作者: cxqghzj

题意

给定一棵树,以及 \(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;
}