P1232 [NOI2013] 树的计数
题目大意
给你一个 dfs 序和一个 bfs 序,求所有满足这两个序的树的高的平均值( 保留三位小数 ),输入保证至少存在一棵树符合给定的两个序列。
解题思路
首先可以从 bfs 序入手,因为更具 bfs 序的性质,可以发现 bfs 序可以分成 个段,每一段中的节点都是在同一行中,而这棵树 的树高 又恰好与 相等。
这里为了方便 ,
记 为点 在 dfs 序的位置。
记 为点 在 bfs 序的位置。
那就可以设有一任意点 ,则 有 种情况:
- 只能分段,;
- 分不分都行,;
- 不能分, 不变。
对于情况 和情况 ,我们可以用一个差分数组 ,记录点 是情况 还是情况 ,
- 若 不为 ,则说明这个地方不设断点或设了断点,若不设断点,则贡献为 ;若设了断点,贡献为 ,但 依旧为 ,因为断点的个数记录在 里就行了 。
- 若 为 ,说明这个地方可以分层也可以不分层,则对平均树高(也就是答案)的贡献为 ,因为如果分层,则贡献为 ;如果不分层,则贡献为 ,综合起来贡献就为 。
再思考情况 ,如果有一个断点,说明满足条件的所有树都应该在这里分层,则对平均树高(也就是答案)的贡献为 。
对于情况 ,我们可以从 bfs 序连续的两点和 dfs 序连续的两点这两个方向入手。
此时显然可以得到一个约束条件,对于 bfs 序连续的两点 ,
- 如果 ,说明 在 的下一层,属于情况 。
- 如果 ,说明 在 的下一层 或 和 在同一层,属于情况 。
再思考 dfs 序连续的两点 ,有 种情况:
- , 和 是兄弟( 没有儿子 );
- , 是 的某个祖先的某个儿子( 没有儿子);
- 是 的儿子,属于情况 。
分析情况 ,发现编号从 到 的所有节点深度差不超过 ,而情况 的贡献在上面已经计算过了,所以情况 在这里的贡献为 ,要在差分数组里面记录一下。另外,记录时要把情况 和情况 筛掉,当然也可以不筛,单独判断 就行了。
AC CODE
#include <bits/stdc++.h>
#define int long long
#define _ (int)2e5 + 5
using namespace std;
int n;
int cc;
int x, y;
double ans = 2.0;
array<int, _> bfn, dfn, b, d, c;
signed main()
{
scanf("%lld", &n);
c[1]++, c[2]--;
for (int i = 1; i <= n; ++i)
{
scanf("%lld", &dfn[i]);
d[dfn[i]] = i;
}
for (int i = 1; i <= n; ++i)
{
scanf("%lld", &bfn[i]);
b[bfn[i]] = i;
}
for (int i = 1; i < n; ++i)
{
x = bfn[i], y = bfn[i + 1];
if (d[x] > d[y])
{
c[i]++, c[i + 1]--;
ans++;
}
x = dfn[i], y = dfn[i + 1];
if ((!(b[x] > b[y])) && (!(b[x] + 1 == b[y]))) //b[x] + 1 < b[y]
{
c[b[x]]++, c[b[y]]--;
}
}
for (int i = 1; i < n; ++i)
{
cc += c[i];
if (!cc)
{
ans += 0.5;
}
}
printf("%.3lf\n", ans);
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122164