[Noi2013]树的计数

做~自己de王妃 提交于 2020-11-27 04:39:39

Description

我们知道一棵有根树可以进行深度优先遍历(DFS)以及广度优先遍历(BFS)来生成这棵树的DFS序以及BFS序。两棵不同的树的DFS序有可能相同,并且它们的BFS序也有可能相同,例如下面两棵树的DFS序都是1 2 4 5 3,BFS序都是1 2 3 4 5

现给定一个DFS序和BFS序,我们想要知道,符合条件的有根树中,树的高度的平均值。即,假如共有K棵不同的有根树具有这组DFS序和BFS序,且他们的高度分别是h1,h2,...,hk,那么请你输出
(h1+h2..+hk)/k

Input

有3行。 
第一行包含1个正整数n,表示树的节点个数。 
第二行包含n个正整数,是一个1~n的排列,表示树的DFS序。 
第三行包含n个正整数,是一个1~n的排列,表示树的BFS序。 
输入保证至少存在一棵树符合给定的两个序列。

Output

仅包含1个实数,四舍五入保留恰好三位小数,表示树高的平均值。

Sample Input


5
1 2 4 5 3
1 2 3 4 5

Sample Output

3.500

HINT

 

【评分方式】

如果输出文件的答案与标准输出的差不超过0.001,则将获得该测试点上的分数,否则不得分。

【数据规模和约定】



20%的测试数据,满足:n≤10;

40%的测试数据,满足:n≤100;

85%的测试数据,满足:n≤2000;

100%的测试数据,满足:2≤n≤200000。

【说明】

树的高度:一棵有根树如果只包含一个根节点,那么它的高度为1。否则,它的高度为根节点的所有子树的高度的最大值加1。

对于树中任意的三个节点a , b , c ,如果a, b都是c的儿子,则a, b在BFS序中和DFS序中的相对前后位置是一致的,即要么a都在b的前方,要么a都在b的后方。

 

Source

这道题没有真的用到BFS和DFS,但需要对BFS和DFS有深刻的认识所以我就做不大出来这道题

首先根据我们对BFS序的理解,BFS序靠前的深度小于BFS序靠后的,所以我们根据BFS序就能划分出树有几层

*DFS序则能确定在同一深度的所有节点的左右顺序

但是这还不够,我们还要更多的条件来确定在什么时候是必须划分的

假设BFS序为1-n按序排列,在[1,2]处是必须分开的,设dfs序列为a[1...n],一个数i的DFS序下一位不为i+1,那么有两种可能:

(1)在i处换行了,而i这一行还有其他数,此时deep[i+1]+1=deep[i] (2)i没有儿子节点,所以向上回溯了

*所以不管怎样,如果i的DFS序下一位不为i+1,deep[i]+1>=deep[i+1]

带星号的两条可以用来判定一种方案的可行性,现在我们可以开始考虑怎么样去统计答案了

设X[i]表示在i和i+1处是否划分,1表示划分0表示不划分,根据上面规则

(1)X[1]=1

(2)if(pos[i]>pos[i+1]) X[i]=1

(3)if(a[i]<a[i+1]) X[a[i]]+X[a[i]+1]+...X[a[i+1]-1]<=1 (因为在dfs序上连续,a[i]和a[i+1]的深度只差最多为1,所以中间的节点最多分一次层) 

通过(1)(2)我们能得出来一部分X=1,带入(3)能得出来一部分X=0

还有一些无法确定,既可能是1也可能是0,我们取个中间值0.5即可

处理的时候对每一段进行差分处理即可

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #define M 200010
 5 using namespace std;
 6 int n,top;
 7 int t[M],a[M],st[M],pos[M],mark[M],s[M];
 8 double ans,X[M];
 9 int main()
10 {
11     scanf("%d",&n);
12     for(int i=1;i<=n;i++)
13     {
14         int k; scanf("%d",&k);
15         t[k]=i;
16     } 
17     for(int i=1;i<=n;i++)
18     {
19         int k; scanf("%d",&k);
20         a[t[k]]=i;
21         pos[i]=t[k];
22     }
23     X[1]=1.0;
24     for(int i=1;i<n;i++)
25     {
26         if(pos[i]>pos[i+1]) X[i]=1.0;
27         if(X[i]==1.0)
28         {
29             mark[i]++;
30             mark[i+1]--;
31         }
32         s[i]=s[i-1]+X[i];
33     }
34     for(int i=1;i<n;i++)
35         if(a[i]<a[i+1])
36         {
37             if(s[a[i+1]-1]-s[a[i]-1]>0)
38             {
39                 mark[a[i]]++;
40                 mark[a[i+1]]--;
41             }
42             else st[++top]=a[i];
43         }
44     for(int i=1;i<=n;i++) mark[i]+=mark[i-1];
45     for(int i=1;i<=top;i++)
46         if(mark[st[i]]==0)
47             X[st[i]]=0.5;
48     for(int i=1;i<=n;i++) ans+=X[i];
49     printf("%.3lf",ans+1.0);
50     return 0;
51 }

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!