P5384 [Cnoi2019] 雪松果树 (找u的k级祖先+树上差分)
本题 trick : o(n) 求k级祖先 ,树上差分
把题目拆成两个部分
1.首先 把u的贡献放到其 k级祖先上,这一部分通过栈来维护每个点的祖先来实现 复杂度 o(n)。为啥这个题要这么做呢?因为通过倍增上去找k级父亲会 T。
2.第二部解决 u的 k级儿子问题,这一部分可以通过树上差分来实现, 具体做法是用桶来维护每一层的数量,然后在第一次访问节点时把对应层数节点的贡献减去然后在整个子树遍历完了之后在加上对应层数节点的贡献加上。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int>pir;
const ll INF = 1e18;
const int N = 1e6 + 5;
std::vector<int> g[N];
std::vector<pir> q[N], h[N];
int st[N], dep[N];
int ans[N], cnt[N];
int top;
void dfs1(int u)
{
st[++top] = u;
for(int v : g[u])
{
dep[v] = dep[u] + 1;
dfs1(v);
}
for(auto [k, id] : q[u])
{
if(dep[u] < k)ans[id] = 1;
else h[st[top - k]].push_back({id, dep[u]});
}
--top;
}
void dfs(int u)
{
for(auto [id, k] : h[u])ans[id] = -cnt[k];
cnt[dep[u]]++;
for( auto v : g[u])
{
dfs(v);
}
for(auto [id, k] : h[u])ans[id] += cnt[k];
}
void solve()
{
int n, m;
cin >> n >> m;
for(int i = 2; i <= n; i++)
{
int fa;
cin >> fa;
g[fa].push_back(i);
}
for(int i = 1; i <= m; i++)
{
int u, k;
cin >> u >> k;
q[u].push_back({k, i});
}
dfs1(1);
top = 0;
dfs(1);
for(int i = 1; i <= m; i++)cout << ans[i] - 1 << " ";
cout << '\n';
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
solve();
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现