您的位置:首页 > 其它

BZOJ3244[NOI2013树的计数]

2015-11-26 23:20 267 查看

Description:

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

Solution:

考虑到 BFS 序的性质,BFS 在前的点的深度一定小于等于后面的点。所以我们考虑根据 BFS 序计算答案。

首先根据 BFS 序给树上的点重编号,按 BFS 序的先后编成 1,2,...,N,考虑相邻的点 i 对答案的贡献,如果它和 i−1必须在不同的层,那么对答案的贡献为 1,如果它和 i−1必须在同一层,那么对答案的贡献为 0 ,否则为 0.5 ,最后只需要把所有的贡献加起来就行了 (1,2号点的贡献应该强制为1)。

必须不在同一层很好判断,考虑一下必须在同一层的情况,如果点i在 DFS 序中的位置在点 i−1 前面的话,那么就一定在不同层。

否则只剩下在必须在同一层或者都可以。

在同一层和不同层都可以的情况,显然需要满足 DFS 序中 i−1,i 两个点必须是连续的。我们画图发现,如果在一棵按 BFS 序编号的树中,点 i 可以变作 i−1 的儿子的并且不改变 DFS,BFS 序的话,只能是 i 变换后, i 所在的那一层只有 i 一个点并且 i,i−1 应该有共同的父亲,那么这个条件等价于 1∼i−1 号点在 DFS 序中 1∼l 的一段和 r∼N 的一段,也就是说在 DFS 序中必须是前面一段最后一段。然后其他情况就是必须在同一层了。

最后记住 BZOJ 上不知道为什么需要输出三行,分别为Ans−0.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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: