BZOJ3244[NOI2013树的计数]

9 篇文章 0 订阅
3 篇文章 0 订阅

Description:

       给定一棵 N(N<=200000) 个节点的树的 DFSBFS `序,求所有满足要求的树的平均深度。
      
      
      

Solution:

       考虑到 BFS 序的性质, BFS 在前的点的深度一定小于等于后面的点。所以我们考虑根据 BFS 序计算答案。
       首先根据 BFS 序给树上的点重编号,按 BFS 序的先后编成 1,2,...,N ,考虑相邻的点 i 对答案的贡献,如果它和 i1必须在不同的层,那么对答案的贡献为 1 ,如果它和 i1必须在同一层,那么对答案的贡献为 0 ,否则为 0.5 ,最后只需要把所有的贡献加起来就行了 ( 1,21 )。
       必须不在同一层很好判断,考虑一下必须在同一层的情况,如果点i在 DFS 序中的位置在点 i1 前面的话,那么就一定在不同层。
       否则只剩下在必须在同一层或者都可以。
       在同一层和不同层都可以的情况,显然需要满足 DFS 序中 i1,i 两个点必须是连续的。我们画图发现,如果在一棵按 BFS 序编号的树中,点 i 可以变作 i1 的儿子的并且不改变 DFS,BFS 序的话,只能是 i 变换后, i 所在的那一层只有 i 一个点并且 i,i1 应该有共同的父亲,那么这个条件等价于 1i1 号点在 DFS 序中 1l 的一段和 rN 的一段,也就是说在 DFS 序中必须是前面一段最后一段。然后其他情况就是必须在同一层了。
       最后记住 BZOJ 上不知道为什么需要输出三行,分别为 Ans0.001,Ans,Ans+0.001
      
      
      

Code:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>

using namespace std;

int N;
int dfs[200010]={0};
int bfs[200010]={0};
int In[200010]={0};
int Max[200010]={0};
int hash[200010]={0};

int main()
{
    cin>>N;
    for(int i=1;i<=N;i++)
    {
        scanf("%d",&dfs[i]);
        In[dfs[i]]=i;
    }
    for(int i=1;i<=N;i++)
    {
        scanf("%d",&bfs[i]);
        dfs[In[bfs[i]]]=i;
        bfs[i]=i;
    }
    for(int i=1;i<=N;i++)
        In[dfs[i]]=i;
    Max[1]=dfs[1];
    for(int i=2;i<=N;i++)
        Max[i]=max(Max[i-1],dfs[i]);
    double Ans=2;
    int l=2,r=N+1;
    hash[1]=hash[2]=1;
    for(int i=3;i<=N;i++)
    {
        if(In[i]<In[i-1])
            Ans+=1;
        else if(In[i]==In[i-1]+1)
        {
            if(l+N+1-r==i-1)
                Ans+=0.5;
        }
        hash[In[i]]=1;
        for(;l<r && hash[l+1]==1;l++);
        for(;l<r && hash[r-1]==1;r--);
    }
    printf("%.3lf\n",Ans);
    //In bzoj printf("%.3lf\n%.3lf\n%.3lf\n",Ans-0.001,Ans,Ans+0.001);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值