CF1610H Squid Game 题解

考虑链怎么做。问题变为给一些区间 $[l_i,r_i]$,选最少的点使得每个 $(l_i,r_i)$ 内都有至少一个点,

这个是贪心经典题,按右端点排序即可,考虑在树上类似地贪心。

钦定 $1$ 为根。可以发现选 $1$ 可以解决所有曲链,不妨先考虑只有直链的情况。

设 $d_u$ 表示 $u$ 的深度。对直链 $u\to v$(钦定 $d_u<d_v$),设 $w$ 为 $v$ 的 $d_v-d_u-1$ 级祖先,

则其要求 $\text{subtree}(w)-\text{subtree}(v)$ 内至少有一个点。

把所有直链按 $d_w$ 从大到小排序,每次若一条链还没有满足要求,选择它的 $w$ 即可,这个贪心容易用数据结构维护。

考虑有曲链的情况。显然若此时所有曲链已经满足要求,答案不变。

否则,此时已选的所有点都无法上移,只能再选一个 $1$ 满足剩下的曲链。

#include <cstdio>
#include <algorithm>
using namespace std;
struct E
{
    int v, t;
} e[1000050];
struct S
{
    int u, v;
} a[1000050], z[1000050];
int n, m, k, r, c, o, q, b[1000050], d[1000050], s[1000050], h[1000050], f[1000050][20], C[1000050];
bool O(S a, S b) { return d[a.u] > d[b.u]; }
void M(int x, int k)
{
    for (; x <= n; x += x & -x)
        ++C[x];
}
int Q(int x, int y)
{
    int q = 0;
    for (--x; y > x; y &= y - 1)
        q += C[y];
    for (; x > y; x &= x - 1)
        q -= C[x];
    return q;
}
void A(int u, int v) { e[++c] = {v, h[u]}, h[u] = c; }
void D(int u, int k)
{
    s[u] = 1;
    b[u] = ++o;
    for (int i = h[u], v; i; i = e[i].t)
        if ((v = e[i].v) != k)
        {
            d[v] = d[f[v][0] = u] + 1;
            for (int j = 1; f[v][j - 1]; ++j)
                f[v][j] = f[f[v][j - 1]][j - 1];
            D(v, u);
            s[u] += s[v];
        }
}
int K(int u, int v)
{
    for (int i = 19; i >= 0; --i)
        if (d[f[v][i]] > d[u])
            v = f[v][i];
    return v;
}
int main()
{
    scanf("%d%d", &n, &m);
    for (int i = 2, x; i <= n; ++i)
        scanf("%d", &x), A(x, i);
    D(1, 0);
    for (int i = 0, u, v; i < m; ++i)
    {
        scanf("%d%d", &u, &v);
        if (d[u] > d[v])
            swap(u, v);
        if (b[v] >= b[u] && b[v] < b[u] + s[u])
        {
            if (d[v] - d[u] <= 1)
            {
                puts("-1");
                return 0;
            }
            a[++k] = {u, v};
        }
        else
            z[++r] = {u, v};
    }
    sort(a + 1, a + k + 1, O);
    for (int i = 1, o; i <= k; ++i)
    {
        o = K(a[i].u, a[i].v);
        if (!Q(b[o], b[a[i].v] - 1) && !Q(b[a[i].v] + s[a[i].v], b[o] + s[o] - 1))
            M(b[o], 1), ++q;
    }
    for (int i = 1; i <= r; ++i)
    {
        if (b[z[i].u] > b[z[i].v])
            swap(z[i].u, z[i].v);
        if (!Q(1, b[z[i].u] - 1) && !Q(b[z[i].u] + s[z[i].u], b[z[i].v] - 1) && !Q(b[z[i].v] + s[z[i].v], n))
        {
            ++q;
            break;
        }
    }
    printf("%d", q);
    return 0;
}
posted @ 2023-12-18 15:14  5k_sync_closer  阅读(3)  评论(0编辑  收藏  举报  来源