Loading

【题解】P2056 [ZJOI2007] 捉迷藏

题意

动态维护树上点集直径。

思路

线段树。

这个题纯粹就是刻板印象检验,结果把我区分了 /xk

谁规定线段树只能维护连续区间?

首先有直径结论:设树上点集 \(S\) 的直径点集为 \(F(S)\),则 \(F(S \cup T) \subset F(S) \cup F(T)\)

于是直径点集具有可合并性,考虑用线段树维护区间直径点集。

合并信息的时候直接分类讨论当前区间的直径端点。

时间复杂度 \(O(n \log n + m \log^2 n)\)

代码

#include <iostream>
#include <vector>
#include <iostream>
using namespace std;

const int maxn = 1e5 + 5;
const int t_sz = maxn << 2;

int n, q;
int fa[maxn], son[maxn], top[maxn], sz[maxn], dep[maxn];
vector<int> g[maxn];

void dfs1(int u, int f)
{
    fa[u] = f, dep[u] = dep[f] + 1, sz[u] = 1;
    for (int v : g[u])
    {
        if (v == f) continue;
        dfs1(v, u);
        sz[u] += sz[v];
        if (sz[v] > sz[son[u]]) son[u] = v;
    }
}

void dfs2(int u, int t)
{
    top[u] = t;
    if (son[u]) dfs2(son[u], t);
    for (int v : g[u])
    {
        if ((v == fa[u]) || (v == son[u])) continue;
        dfs2(v, v);
    }
}

int lca(int u, int v)
{
    while (top[u] != top[v])
    {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        u = fa[top[u]];
    }
    return (dep[u] < dep[v] ? u : v);
}

int dis(int u, int v) { return dep[u] + dep[v] - 2 * dep[lca(u, v)]; }

namespace SGT
{
    int u[t_sz], v[t_sz], w[t_sz];

    void get_max(int k, int _u, int _v, int _w) { if (_w > w[k]) u[k] = _u, v[k] = _v, w[k] = _w; }

    void push_up(int k)
    {
        int ls = (k << 1), rs = (k << 1 | 1);
        w[k] = -1;
        get_max(k, u[ls], v[ls], w[ls]);
        get_max(k, u[rs], v[rs], w[rs]);
        if ((w[ls] == -1) || (w[rs] == -1)) return;
        get_max(k, u[ls], u[rs], dis(u[ls], u[rs]));
        get_max(k, u[ls], v[rs], dis(u[ls], v[rs]));
        get_max(k, v[ls], u[rs], dis(v[ls], u[rs]));
        get_max(k, v[ls], v[rs], dis(v[ls], v[rs]));
    }

    void build(int k, int l, int r)
    {
        if (l == r)
        {
            u[k] = v[k] = l, w[k] = 0;
            return;
        }
        int mid = (l + r) >> 1;
        build(k << 1, l, mid);
        build(k << 1 | 1, mid + 1, r);
        push_up(k);
    }

    void update(int k, int l, int r, int p)
    {
        if (l == r)
        {
            if (w[k] == -1) u[k] = v[k] = l, w[k] = 0;
            else u[k] = v[k] = 0, w[k] = -1;
            return;
        }
        int mid = (l + r) >> 1;
        if (p <= mid) update(k << 1, l, mid, p);
        else update(k << 1 | 1, mid + 1, r, p);
        push_up(k);
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> n;
    for (int i = 1, u, v; i <= n - 1; i++)
    {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs1(1, 0);
    dfs2(1, 1);
    SGT::build(1, 1, n);
    cin >> q;
    while (q--)
    {
        char opt;
        cin >> opt;
        if (opt == 'C')
        {
            int u;
            cin >> u;
            SGT::update(1, 1, n, u);
        }
        else printf("%d\n", SGT::w[1]);
    }
    return 0;
}
posted @ 2023-01-13 15:52  kymru  阅读(15)  评论(0编辑  收藏  举报