[Noi2013]树的计数

来自FallDream的博客,未经允许,请勿转载,谢谢。


我们知道一棵有根树可以进行深度优先遍历(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

n<=200000

对bfs序分层  考虑同时符合dfs和bfs序的树满足什么条件 

1.对于bfs连续的ab两点,假如a的bfs序小于b的bfs序,且a的dfs序大于b的,那么他们之间肯定是要分层的 

2.另外 dfs序连续的ab两点,假如a的dfs序小于b的,且a的bfs序也小于b,那么显然它们的深度差不超过1,也就是说它们的bfs序区间之间最多分一层

3.第一个点要强制分层

所以考虑先把13条件都判一下,求出分层数的前缀和数组,然后把第2个条件判一下(如果它们之间已经分层了,那么就强制其他的不分层)

最后还没确定的点可分层可不分,贡献是0.5,答案是分层数加1再加上没确定的点的数量乘以0.5

复杂度O(n)

#include<iostream>
#include<cstdio>
#define getchar() (*S++)
#define MN 200000
char BB[1<<26],*S=BB;
using namespace std;
inline int read()
{
    int x = 0; char ch = getchar();
    while(ch < '0' || ch > '9') ch = getchar();
    while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
    return x;
}

int D[MN+5],P[MN+5],B[MN+5],n,ans=0,x[MN+5],y[MN+5],q[MN+5],top=0;
inline void mark(int a,int b){++y[a];--y[b];}

int main()
{
    fread(BB,1,1<<26,stdin);
    n=read();int j;
    for(register int i=1;i<=n;++i) P[j=read()]=i;
    for(register int i=1;i<=n;++i) D[B[i]=P[j=read()]]=i;
    for(register int i=1;i<n;++i)
        x[i]=x[i-1],(i==1||B[i]>B[i+1])?(ans+=2,++x[i],mark(i,i+1),0):0;
    for(register int i=1;i<n;++i) D[i]<D[i+1]?(x[D[i+1]-1]>x[D[i]-1]?(mark(D[i],D[i+1]),0):q[++top]=D[i]):0;
    for(register int i=1;i<=n;++i) y[i]+=y[i-1];
    for(register int i=1;i<=top;++i) ans+=y[q[i]]==0;
    double Ans=(double)ans/2+1;
    printf("%0.3lf
%0.3lf
%0.3lf",Ans-0.001,Ans,Ans+0.001);
    return 0;
}
原文地址:https://www.cnblogs.com/FallDream/p/noi2013d1t2.html