NOI2013 树的计数

NOI2013 树的计数

给定一个dfs序和bfs序,求解符合这两个条件的所有树的平均树高。

思路

如果我们能够给bfs序中每一段区间分层,然后再去对应dfs序,不难发现可以唯一确定一棵树,即在dfs的过程中,前后两个节点的关系可以按照层数来判断,分为儿子或者是某一层祖先的另外一个儿子。

而给bfs序分层的时候我们需要满足一些限制:

  1. bfs序中同一层在dfs中访问顺序必须严格按照bfs的访问顺序来。
  2. dfs中每一次只能往下走一层或者是往上走若干层或者还停留在这一层。
  3. 1号点必须要分层。

接下来考虑怎么求解树高,bfs按照限制分完层之后会有一些断点,我们可以求出在满足限制的情况下每一个点成为端点的期望是多少,最后根据期望的线性性直接相加就可以得到最后的答案。

考虑如何去满足这些限制。

从1号限制的逆否命题可以退出,如果相邻的两个点在dfs中没有按照编号的顺序来,那么它们一定不在同一层,即pos[i]>pos[i+1],那么可以肯定i一定是断点,不难发现满足了这个限制就满足了1号限制。

  1. 在dfs序中相邻的两个点d[i],d[i+1],如果d[i+1] < d[i],那么i+1一定是i某一个祖先的另一个儿子,它们之间的断点个数是可以任意的。

  2. 如果d[i+1]>d[i]+1,它们一定不是兄弟的关系,也就是这两个点只能做父子,并且它们之间的断点个数一定为1,也就是我们可以标记这中间所有的点,它们都是已经确定的。

  3. 如果d[i+1]=d[i]+1,它们既可以做父子又可以做兄弟,它们之间的关系也是任意的。

但是上面1.3情况的任意取值都受2情况的影响,我们标记所有2情况影响的点,然后对于剩下的没有标记的点就可以任意取值,期望为0.5。

最后的答案就是确定为1的点加上期望为0.5的点。

// luogu-judger-enable-o2
/*=======================================
 * Author : ylsoi
 * Time : 2019.6.18
 * Problem : luogu1232
 * E-mail : ylsoi@foxmail.com
 * ====================================*/
#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a,i##_end_=b;i<=i##_end_;++i)
#define DREP(i,a,b) for(int i=a,i##_end_=b;i>=i##_end_;--i)
#define debug(x) cout<<#x<<"="<<x<<" "
#define fi first
#define se second
#define mk make_pair
#define pb push_back
typedef long long ll;

using namespace std;

void File(){
    freopen("luogu1232.in","r",stdin);
    freopen("luogu1232.out","w",stdout);
}

template<typename T>void read(T &_){
    _=0; T f=1; char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())_=(_<<1)+(_<<3)+(c^'0');
    _*=f;
}

string proc(){
    ifstream f("/proc/self/status");
    return string(istreambuf_iterator<char>(f),istreambuf_iterator<char>());
}

const int maxn=2e5+10;
int n,b[maxn],d[maxn],pb[maxn],pd[maxn],vis[maxn];
double ans;

int main(){
    //File();

    read(n);
    REP(i,1,n)read(d[i]);
    REP(i,1,n)read(b[i]),pb[b[i]]=i;
    REP(i,1,n)d[i]=pb[d[i]],pd[d[i]]=i;
    REP(i,2,n-1){
        if(pd[i]>pd[i+1])ans+=1,++vis[i],--vis[i+1];
        if(d[i]+1<d[i+1])++vis[d[i]],--vis[d[i+1]];
    }
    REP(i,3,n)vis[i]+=vis[i-1];
    REP(i,2,n-1)if(!vis[i])ans+=0.5;
    printf("%.3lf\n",ans+2);

    return 0;
}
posted @ 2019-06-18 19:04  ylsoi  阅读(197)  评论(0编辑  收藏  举报