P8805 [蓝桥杯 2022 国 B] 机房
1.试题 C :直线2.树形动态规划3.X 进制减法4.后缀表达式5.统计子矩阵6.包子凑数7.整数拼接8.地宫取宝9.七段码10.砝码称重11.递增三元组12.完全平方数13.[蓝桥杯 2019 省 A] 填空问题 E14.波动数列15.左孩子右兄弟16.接龙数列17.糖果18.蚂蚁感冒19.子串分值20.超级胶水21.P9425 [蓝桥杯 2023 国 B] AB 路线22.P9426 [蓝桥杯 2023 国 B] 抓娃娃23.P9425 [蓝桥杯 2022 国 B] 2022
24.P8805 [蓝桥杯 2022 国 B] 机房
25.P8806 [蓝桥杯 2022 国 B] 搬砖26.P8764 [蓝桥杯 2021 国 BC] 二进制问题一、问题简析
本题核心思想是求最近公共祖先,这里采用 \(Tarjan\) 算法求解。
以节点 \(1\) 作为树的根节点。令 \(dp_i=\) 节点 \(i\) 到根节点 \(1\) 的点权和; \(w_i\) 为节点 \(i\) 的权值,即该节点的度; 节点 \(t_i\) 为第 \(i\) 个疑问中,节点 \(u_i\) 和 \(v_i\) 的 \(LCA\),则第 \(i\) 个疑问的答案是
\[ans_i=dp_{u_i}+dp_{v_i}-2*dp_{t_i}+w_{t_i}
\]
解释:因为 \(t_i\) 为 \(u_i\) 和 \(v_i\) 的 \(LCA\),所以从 \(u_i\) 到 \(v_i\) 必然经过 \(t_i\)。\(dp_{u_i}-dp_{t_i}\) 为 \(u_i\) 到 \(t_i\) (除 \(t_i\))的点权和,而\(dp_{v_i}-dp_{t_i}\) 为 \(v_i\) 到 \(t_i\) (除 \(t_i\))的点权和。二者相加后,再加上 \(t_i\) 的权值,即为所求。
二、Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll quickin(void)
{
ll ret = 0;
bool flag = false;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-') flag = true;
ch = getchar();
}
while (ch >= '0' && ch <= '9' && ch != EOF)
{
ret = ret * 10 + ch - '0';
ch = getchar();
}
if (flag) ret = -ret;
return ret;
}
typedef pair<int, int> P;
const int MAX = 1e5 + 5;
int N, M;
vector<int> G[MAX];
vector<P> query[MAX];
bool vis[MAX];
int fa[MAX];
ll d[MAX], dp[MAX], ans[MAX]; // d[i] -- 节点i的度; dp[i] -- 节点i到根节点1的点权和
void init(void)
{
for (int i = 1; i <= N; ++i)
fa[i] = i;
}
int find(int x)
{
if (fa[x] == x) return x;
else return fa[x] = find(fa[x]);
}
void tarjan(int u)
{
vis[u] = true;
for (auto v : G[u])
{
if (!vis[v])
{
tarjan(v);
fa[v] = u;
}
}
for (auto p : query[u])
{
int v = p.first, id = p.second;
if (vis[v])
{
int t = find(v); // u和v的LCA
ans[id] = dp[u] + dp[v] - 2 * dp[t] + d[t];
}
}
}
void dfs(int u, int fa)
{
dp[u] = dp[fa] + d[u];
for (auto v : G[u])
{
if (v != fa)
{
dfs(v, u);
}
}
}
int main()
{
#ifdef LOCAL
freopen("test.in", "r", stdin);
#endif
N = quickin(), M = quickin();
for (int i = 1; i < N; ++i)
{
int a, b;
a = quickin(), b = quickin();
G[a].push_back(b), G[b].push_back(a);
++d[a], ++d[b];
}
for (int i = 0; i < M; ++i)
{
int a, b;
a = quickin(), b = quickin();
query[a].push_back(P(b, i));
query[b].push_back(P(a, i));
}
init();
dfs(1, 0);
tarjan(1);
for (int i = 0; i < M; ++i)
cout << ans[i] << endl;
return 0;
}
完
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具