Atcoder Beginner Round #274 C题 Ameba 题解
\(\texttt{diff: }\color{gray}{315}\)
题意:给定一颗二叉树,问 \(1\) 号节点是 \(i\) 号节点的多少代祖先,\(i\) 是 \(1\sim 2n + 1\) 中的所有整数。
题解:
因为这道题的难度只有 \(315\),所以一定是使用很简单的方法,所以用非常简单的树剖的树上差分写。
由于 \(1\) 号节点是根节点,所以问 \(1\) 是 \(i\) 的多少代祖先就是问 \(1\sim i\) 的距离。
那么就可以在 \(O(n\log n)\) 的时间里求出答案了。
Tips:
树剖需要建双向边。
比如说建边部分:
// 随便举了一个栗子
void add(int a)
{
z[a].push_back(i << 1);
z[i << 1].push_back(a);
// a<<1|1 同理
}
代码:
#include <bits/stdc++.h>
using namespace std;
int n, m;
const int N = 9e5 + 10;
int a[N];
vector <int> z[N];
int dfs_order[N], rk[N], cnt, top[N], len[N], fa[N], sz[N], dep[N], son[N];
void dfs1(int now, int fa = -1)
{
if (now == 9)
{
cerr << "now 'now' = 9.\n";
cerr << fa << ' ' << ::fa[now] << '\n';
}
dep[now] = dep[::fa[now]] + 1;
sz[now] = 1;
for (auto &u : z[now])
{
if (u == fa)
continue ;
::fa[u] = now;
dfs1(u, now);
sz[now] += sz[u];
if (sz[u] > sz[son[now]])
son[now] = u;
}
}
void dfs2(int now, int h, int fa = -1)
{
cnt ++;
dfs_order[cnt] = now;
rk[now] = cnt;
top[now] = h;
len[h] ++;
int p = -1;
for (auto &u : z[now])
{
if (u == fa)
continue ;
if (p == -1)
p = u;
else if (sz[u] > sz[p])
p = u;
}
if (p == -1)
return ;
dfs2(p, h, now);
for (auto &u : z[now])
if (p != u && u != fa)
dfs2(u, u, now);
}
int lca(int x, int y)
{
while (top[x] != top[y])
{
if (dep[top[x]] < dep[top[y]])
swap (x, y);
x = fa[top[x]];
}
if (dep[x] < dep[y])
return x;
return y;
}
int qdis(int u, int v)
{
return dep[u] + dep[v] - 2 * dep[lca(u, v)];
}
signed main()
{
cin >> n;
for (int i = 1; i <= n; i ++)
{
int x;
cin >> x;
z[x].push_back(i << 1);
z[x].push_back(i << 1 | 1);
z[i << 1].push_back(x);
z[i << 1 | 1].push_back(x);
}
dfs1(1);
dfs2(1, 1);
for (int i = 1; i <= 9; i ++)
cerr << dep[i] << ' ';
cerr << '\n';
for (int i = 1; i <= (n << 1 | 1); i ++)
cout << qdis(1, i) << '\n';
return 0;
}
本文来自博客园,作者:yhbqwq,转载请注明原文链接:https://www.cnblogs.com/yhbqwq/p/16818558.html,谢谢QwQ