传送门
题意:给定一棵nnn个点的树的DFS和BFS序,求树高期望。
n≤2e5n \leq 2e5n≤2e5
首先根据BFS序将树点分层,一定切记先自己把树点分层,这样实际上是在排除一部分情况。
将每一层第一个点打标记,答案就是期望标记个数。
首先BFS序第一个和第二个一定有标记。
对于之后BFS序相邻的两个,如果后面的DFS序小于前面的,说明这里分了层,给后面打上标记。
还有一个限制,DFS序相邻的两个点,后面最多比前面深一层。所以用前面的标记算出层数,如果后面大于前面,用差分实现区间修改为-1,表示一定没有标记。
而剩下的点可分可不分,贡献0.50.50.5
复杂度O(n)O(n)O(n)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 200005
using namespace std;
inline int read()
{int ans=0;char c=getchar();while (!isdigit(c)) c=getchar();while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();return ans;
}
int dfs[MAXN],bfs[MAXN],dfn[MAXN],bfn[MAXN];
int mark[MAXN],dep[MAXN],s[MAXN];
int main()
{int n=read();for (int i=1;i<=n;i++) dfn[dfs[i]=read()]=i;for (int i=1;i<=n;i++) bfn[bfs[i]=read()]=i;dep[bfs[1]]=dep[bfs[2]]=mark[bfs[1]]=mark[bfs[2]]=1;for (int i=2;i<n;i++)if (dfn[bfs[i+1]]<dfn[bfs[i]])dep[bfs[i+1]]=mark[bfs[i+1]]=1;for (int i=1;i<=n;i++) cerr<<mark[i]<<endl; for (int i=1;i<=n;i++) dep[bfs[i]]+=dep[bfs[i-1]];for (int i=1;i<n;i++)if (dep[dfs[i]]<dep[dfs[i+1]])++s[bfn[dfs[i]]+1],--s[bfn[dfs[i+1]]+1];for (int i=1;i<=n;i++) cerr<<s[i]<<endl;for (int i=1;i<=n;i++)if ((s[i]+=s[i-1])>0&&!mark[bfs[i]])mark[bfs[i]]=-1;for (int i=1;i<=n;i++) cerr<<mark[i]<<endl;double ans=0;for (int i=1;i<=n;i++)if (mark[i]==1) ans+=1;else if (mark[i]==0) ans+=0.5;printf("%.3f",ans);return 0;
}