洛谷题单指南-图论之树-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;
}
浙公网安备 33010602011771号