CF 983E NN country

题意

给定一棵 \(n\) 个点的树和 \(m\) 条树上路径,\(q\) 次询问 \(x\to y\) 最少用多少条路径。

\(n, m, q\leq 2\times 10 ^5\)

题解

有一个贪心策略:我们考虑同时操作 \(x\)\(y\),每次让它们跳到能跳到的最浅的点。直到跳到再往上跳就超过 \(lca\) 了为止。此时如果有一条路径同时经过了 \(x'\)\(y'\),那么只需要再跳一次,否则要 \(x'\)\(y'\) 需要再同时往上跳一步。

我们搞一个倍增数组 \(jmp[u][i]\) 表示 \(u\) 向上跳 \(2^i\) 次能跳到的最浅的点。

考虑判断是否有路径经过 \(x\)\(y\)。离线所有询问。我们在 \(dfs\)\(x\) 的时候,如果有以 \(x\) 为起点的路径,就给对应的终点打标记。如果在进入 \(x\) 子树的时候和回溯的时候 \(y\) 子树内的标记数不一样,说明存在路径。可以使用树状数组维护。

注意额外判无解,\(x\)\(y\)\(lca\) 的情况。

#include <bits/stdc++.h>

const int N = 2e5 + 10;
#define pii std::pair<int, int>
#define mkp(a, b) std::make_pair(a, b)

inline int read()
{
    int x = 0;
    char ch = getchar();
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
    return x;
}

struct Bit
{
    int f[N];
    #define lowbit(x) (x & -x)

    inline void Add(int x)
    {
        for (; x < N; x += lowbit(x)) f[x]++;
    }

    inline int Ask(int x)
    {
        int res = 0;
        for (; x; x -= lowbit(x)) res += f[x];
        return res;
    }

    inline int Ask(int l, int r)
    {
        return Ask(r) - Ask(l - 1);
    }
}T;

std::vector<pii> V[N];
std::vector<int> G[N], F[N];
int tot = 1, fir[N], nex[N << 1], got[N << 1], ans[N], res[N], flg[N];
int idx = 1, dep[N], siz[N], dfn[N], rev[N], par[N][21], jmp[N][21];

inline int cmp(int a, int b) {return dep[a] < dep[b] ? a : b;}

inline void AddEdge(int u, int v)
{
    nex[++tot] = fir[u], fir[u] = tot, got[tot] = v;
    nex[++tot] = fir[v], fir[v] = tot, got[tot] = u;
}

inline void dfs(int u, int fa)
{
    dep[u] = dep[par[u][0] = fa] + 1, siz[u] = 1, dfn[u] = ++idx, rev[idx] = u;
    for (int i = 1; i <= 20; ++i) par[u][i] = par[par[u][i - 1]][i - 1];
    for (int i = fir[u]; i; i = nex[i]) if (got[i] != fa) dfs(got[i], u), siz[u] += siz[got[i]];
}

inline int getlca(int u, int v)
{
    if (dep[u] < dep[v]) std::swap(u, v);
    for (int i = 20; i >= 0; --i) if (dep[par[u][i]] >= dep[v]) u = par[u][i];
    if (u == v) return u;
    for (int i = 20; i >= 0; --i) if (par[u][i] != par[v][i]) u = par[u][i], v = par[v][i];
    return par[u][0];
}

inline void Dfs(int u, int fa)
{
    jmp[u][0] = u;
    for (auto v: G[u]) jmp[u][0] = cmp(jmp[u][0], getlca(u, v));
    for (int i = fir[u]; i; i = nex[i]) if (got[i] != fa) 
        Dfs(got[i], u), jmp[u][0] = cmp(jmp[u][0], jmp[got[i]][0]);
}

inline int jump(int &u, int lca)
{
    int res = 0;
    for (int i = 20; i >= 0; --i)
        if (dep[jmp[u][i]] > dep[lca] && (i || jmp[u][i] != jmp[u][i - 1])) u = jmp[u][i], res = 1 << i;
    return res;
}

inline void dfS(int u, int fa)
{
    std::vector<int> vec(V[u].size());
    for (int i = 0; i < V[u].size(); ++i)
    {
        int v = V[u][i].first;
        vec[i] = T.Ask(dfn[v], dfn[v] + siz[v] - 1);
    }
    for (auto v: G[u]) T.Add(dfn[v]);
    for (int i = fir[u]; i; i = nex[i]) if (got[i] != fa) dfS(got[i], u);
    for (int i = 0; i < V[u].size(); ++i)
    {
        int v = V[u][i].first, w = V[u][i].second;
        if (vec[i] != T.Ask(dfn[v], dfn[v] + siz[v] - 1)) flg[w] = true;
    }
}

int main()
{
    int n = read();
    for (int i = 2; i <= n; ++i) AddEdge(i, read());
    int m = read(); dfs(1, 0);
    for (int i = 1; i <= m; ++i)
    {
        int u = read(), v = read();
        G[u].push_back(v), G[v].push_back(u);
    }
    int q = read(); Dfs(1, 0);
    for (int i = 1, u; u = rev[i], i <= n; ++i)
        for (int j = 1; j <= 20; ++j) jmp[u][j] = jmp[jmp[u][j - 1]][j - 1];
    for (int t = 1; t <= q; ++t)
    {
        int u = read(), v = read(), lca = getlca(u, v);
        if (u == v) {res[t] = flg[t] = true; continue;}
        // F[u].push_back(v), F[v].push_back(u);
        ans[t] = jump(u, lca) + jump(v, lca) + 1;
        if (u == lca || v == lca)
        {
            if (u == lca) std::swap(u, v);
            if (dep[jmp[u][0]] <= dep[lca]) res[t] = flg[t] = true;
        }
        else
        {
            int fu = jmp[u][0], fv = jmp[v][0];
            if (dep[fu] <= dep[lca] && dep[fv] <= dep[lca]) res[t] = true;
            V[u].emplace_back(v, t);
            V[v].emplace_back(u, t);
        }
    }
    dfS(1, 0);
    for (int i = 1; i <= q; ++i) printf("%d\n", res[i] ? ans[i] + 1 - flg[i] : -1);
    return 0;
}

posted @ 2020-10-15 15:34  bo1949  阅读(126)  评论(0)    收藏  举报