洛谷题单指南-图论之树-P4092 [HEOI2016/TJOI2016] 树
原题链接:https://www.luogu.com.cn/problem/P4092
题意解读:树支持两种操作:1、单点修改,将某个点打标记 2、路径查询,找到某个点最近打过标记的祖先
解题思路:
依然是一个重链剖分+线段树的题目,有两个关键点
1、区间查询是什么?
要知道某个节点最近打过标记的祖先,在重链剖分后的dfs序中,就是要在节点到根节点之间找一个打过标记的dfs序最大的节点。
2、线段树维护什么?
根据以上分析,线段树只需维护区间中打过标记的最右边的节点即可,对应树上就是dfs序最大的节点。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
vector<int> g[N];
struct Node
{
int l, r;
int maxtag; //区间最右边一个打了标记的节点
} 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].maxtag = max(tr[u << 1].maxtag, tr[u << 1 | 1].maxtag);
}
void build(int u, int l, int r)
{
tr[u] = {l, r};
if(l == r) tr[u].maxtag = 0;
else
{
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
//将pos位置标记修改为true
void update(int u, int pos)
{
if(tr[u].l == tr[u].r) tr[u].maxtag = tr[u].l;
else
{
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最右边的tag=true的节点
int query(int u, int l, int r)
{
if(tr[u].l >= l && tr[u].r <= r) return tr[u].maxtag;
else if(tr[u].l > r || tr[u].r < l) return 0;
return max(query(u << 1, l, r), query(u << 1 | 1, l, r));
}
//找到u~1路径上打标记的点中dfn序最大的点
int queryPath(int u)
{
while(top[u])
{
int res = query(1, dfn[top[u]], dfn[u]);
if(res) return res;
u = fa[top[u]];
}
return 0;
}
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);
update(1, dfn[1]);
while(m--)
{
char op;
int x;
cin >> op >> x;
if(op == 'C') update(1, dfn[x]);
else if(op == 'Q') cout << rk[queryPath(x)] << endl;
}
return 0;
}
浙公网安备 33010602011771号