洛谷题单指南-图论之树-P4116 Qtree3

原题链接:https://www.luogu.com.cn/problem/P4116

题意解读:一棵树,初始节点颜色都是白色,支持两个操作:1、单点修改,将节点颜色从黑->白或者从白->黑 2、查询根节点1到节点x路径上第一个黑色节点

解题思路:

跟上一道题基本类似,又是树链剖分+线段树的典型应用,稍微不同的是

1、单点修改操作,可以将颜色进行黑白切换

2、查询节点的父节点中,最靠近根的黑色节点

因此,本题关键点有两点:

1、线段树维护的信息是区间最左边的黑色节点编号

2、对1-x路径查询的黑色节点在dfs序中排序是最小的

剩下的代码就比较好写了。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 100005, INF = 1e9;

vector<int> g[N];
struct Node
{
    int l, r;
    int mintag; //区间最左边一个黑色的节点
} tr[N * 4];
int son[N], siz[N], fa[N], depth[N], top[N], dfn[N], rk[N], cnt;
int n, m;

void dfs1(int u, int p, int d)
{
    depth[u] = d;
    fa[u] = p;
    siz[u] = 1;
    for(auto v : g[u])
    {
        if(v == p) continue;
        dfs1(v, u, d + 1);
        siz[u] += siz[v];
        if(siz[v] > siz[son[u]]) son[u] = v;
    }
}

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

void pushup(int u)
{
    tr[u].mintag = min(tr[u << 1].mintag, tr[u << 1 | 1].mintag);
}

void build(int u, int l, int r)
{
    tr[u] = {l, r};
    if(l == r) 
    {
        tr[u].mintag = INF;
        return;
    }
    int mid = l + r >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
    pushup(u);
}

//将pos位置颜色黑->白,白->黑
void update(int u, int pos)
{
    if(tr[u].l == tr[u].r) 
    {
        if(tr[u].mintag == INF) tr[u].mintag = tr[u].l;
        else tr[u].mintag = INF;
        return;
    }
    int mid = tr[u].l + tr[u].r >> 1;
    if(pos <= mid) update(u << 1, pos);
    else update(u << 1 | 1, pos);
    pushup(u);
}

//找区间l~r最左边的颜色是黑色的节点
int query(int u, int l, int r)
{
    if(tr[u].l >= l && tr[u].r <= r) return tr[u].mintag;
    else if(tr[u].l > r || tr[u].r < l) return INF;
    return min(query(u << 1, l, r), query(u << 1 | 1, l, r));
}

//找到u~1路径上dfn序最小的黑色点
int queryPath(int u)
{
    int res = INF;
    while(top[u])
    {
        res = min(res, query(1, dfn[top[u]], dfn[u]));
        u = fa[top[u]];
    }
    return res;
}

int main()
{
    cin >> n >> m;
    for(int i = 1; i < n; i++)
    {
        int u, v;
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    dfs1(1, 0, 1);
    dfs2(1, 1);
    build(1, 1, n);
    while(m--)
    {
        int op, x;
        cin >> op >> x;
        if(op == 0) update(1, dfn[x]);
        else if(op == 1) 
        {
            int res = queryPath(x);
            cout << (res == INF ? -1 : rk[res]) << endl;
        }
    }
    return 0;
}

 

posted @ 2025-03-26 14:48  hackerchef  阅读(43)  评论(0)    收藏  举报