题意:给你DFS序和BFS序,求树的期望高度。

解:先分析性质。

考虑到BFS序是分层的,DFS序的子树是一段,那么我们遍历BFS序并在DFS序上标记对应点的话,就会发现BFS序每一层都会把若干棵子树每个都分成若干个小子树,且换层的时候一定会是DFS序上第一个非空位置。

设每个点的期望深度为hi,那么就是要求BFS序最后一个点的h。考虑每个点的深度怎么算。如果当前点不是新一层的开头,那么它的h一定等于他在BFS序前面一个点的深度。如果是开头,那么就要等于它父亲的深度 + 1,我们可以在DFS序上把每个点的子树染色以查明该点的父亲。如果这两种情况都有可能,那么h就是这两种情况的平均数。

考虑什么时候只可能是一种情况。

当这个点在DFS序上的位置前于BFS序上前一个点在DFS序上的位置的时候,当前点一定是新一层的开头。

当这个点在DFS序上的位置后与BFS序上前一个点在DFS序上的位置的时候:如果这个点和BFS上前一个点在DFS序上的位置不相邻,那么这两个点一定在同一层。

相邻的时候,如果当前点在DFS序的前面还有空位,那么一定在同一层。否则考虑这个子树后面还有没有空位,如果有也一定在同一层,因为要换层的话一定要把后面的每个都走一遍。

实现的时候就用线段树维护颜色和区间和。

 #include <bits/stdc++.h>

 const int N = ;

 int col[N << ], sum[N << ];
int d[N], b[N], pos[N];
double h[N]; inline void pushdown(int o) {
if(!col[o]) return;
col[o << ] = col[o << | ] = col[o];
col[o] = ;
return;
} void add(int p, int l, int r, int o) {
if(l == r) {
sum[o] = ;
return;
}
int mid = (l + r) >> ;
if(p <= mid) add(p, l, mid, o << );
else add(p, mid + , r, o << | );
sum[o] = sum[o << ] + sum[o << | ];
return;
} int getSum(int L, int R, int l, int r, int o) {
if(L <= l && r <= R) return sum[o];
int mid = (l + r) >> , ans = ;
if(L <= mid) ans += getSum(L, R, l, mid, o << );
if(mid < R) ans += getSum(L, R, mid + , r, o << | );
return ans;
} void change(int L, int R, int v, int l, int r, int o) {
if(L <= l && r <= R) {
col[o] = v;
return;
}
pushdown(o);
int mid = (l + r) >> ;
if(L <= mid) change(L, R, v, l, mid, o << );
if(mid < R) change(L, R, v, mid + , r, o << | );
return;
} int ask(int p, int l, int r, int o) {
if(l == r) return col[o];
int mid = (l + r) >> ;
pushdown(o);
if(p <= mid) return ask(p, l, mid, o << );
else return ask(p, mid + , r, o << | );
} int getKth(int k, int l, int r, int o) {
if(l == r) {
return r + (k > sum[o]);
}
int mid = (l + r) >> ;
if(k <= sum[o << ]) {
return getKth(k, l, mid, o << );
}
else {
return getKth(k - sum[o << ], mid + , r, o << | );
}
} int main() { int n;
scanf("%d", &n);
for(int i = ; i <= n; i++) {
scanf("%d", &d[i]);
pos[d[i]] = i;
}
for(int i = ; i <= n; i++) {
scanf("%d", &b[i]);
}
/// h[1] = 1
for(int i = ; i <= n; i++) {
/// b[i] in pos[b[i]]
int p = pos[b[i]], lastp = pos[b[i - ]];
add(p, , n, );
int s = getSum(, p, , n, );
int ed = getKth(s + , , n, ) - ;
/// [p, ed]
if(i == ) {
h[b[i]] = ;
}
else if(p == lastp + && s == p && (ed < n ? getSum(ed + , n, , n, ) : ) == n - ed) {
int fr = ask(p, , n, );
if(fr != d[]) h[b[i]] = (h[fr] + + h[b[i - ]]) / ;
else h[b[i]] = h[fr] + ;
}
else if(p < lastp) { /// new line
int fr = ask(p, , n, );
h[b[i]] = h[fr] + ;
}
else {
h[b[i]] = h[b[i - ]];
}
change(p, ed, b[i], , n, );
} printf("%.3f\n", h[b[n]]);
return ;
}

AC代码

LOJ#2665 树的计数的更多相关文章

  1. loj#2665. 「NOI2013」树的计数

    目录 题目链接 题解 代码 题目链接 loj#2665. 「NOI2013」树的计数 题解 求树高的期望 对bfs序分层 考虑同时符合dfs和bfs序的树满足什么条件 第一个点要强制分层 对于bfs序 ...

  2. 树的计数 + prufer序列与Cayley公式 学习笔记

    首先是 Martrix67 的博文:http://www.matrix67.com/blog/archives/682 然后是morejarphone同学的博文:http://blog.csdn.ne ...

  3. 【BZOJ】【1211】【HNOI2004】树的计数

    Prufer序列+组合数学 嗯哼~给定每个点的度数!求树的种数!那么很自然的就想到是用prufer序列啦~(不知道prufer序列的……自己再找找资料吧,这里就不放了,可以去做一下BZOJ1005明明 ...

  4. BZOJ1211: [HNOI2004]树的计数

    1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1245  Solved: 383[Submit][Statu ...

  5. BZOJ 1211: [HNOI2004]树的计数( 组合数学 )

    知道prufer序列就能写...就是求个可重集的排列...先判掉奇怪的情况, 然后答案是(N-2)!/π(d[i]-1)! -------------------------------------- ...

  6. 「NOI2013」树的计数 解题报告

    「NOI2013」树的计数 这什么神题 考虑对bfs重新编号为1,2,3...n,然后重新搞一下dfs序 设dfs序为\(dfn_i\),dfs序第\(i\)位对应的节点为\(pos_i\) 一个暴力 ...

  7. 【BZOJ 1211】 1211: [HNOI2004]树的计数 (prufer序列、计数)

    1211: [HNOI2004]树的计数 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2468  Solved: 868 Description 一 ...

  8. bzoj1211: [HNOI2004]树的计数 prufer编码

    题目链接 bzoj1211: [HNOI2004]树的计数 题解 prufer序 可重排列计数 代码 #include<bits/stdc++.h> using namespace std ...

  9. UOJ #122 【NOI2013】 树的计数

    题目链接:树的计数 这道题好神啊……正好有人讲了这道题,那么我就写掉吧…… 首先,为了方便考虑,我们可以把节点重标号,使得\(bfs\)序变成\(1,2,3,\dots,n\),那么显然树的深度就是\ ...

随机推荐

  1. iOS----------use_frameworks!

    1.https://segmentfault.com/a/1190000007076865 2.https://www.jianshu.com/p/8269e4cac48f 3.https://www ...

  2. Android Interpolator解析

    本文部分图片转自:https://blog.csdn.net/lgaojiantong/article/details/39451243 目录 自定义插值器 系统插值器 1. 自定义插值器 要自定义插 ...

  3. 浏览器与android移动端视频互播技术实现

    手机端与平台之间的视频直播功能,主要通过集成多种开源视频框架以及采购第三方视频直播服务器产品来实现预定业务需求.视频直播对话功能的实现,主要经历了三个阶段:利用开源视频框架实现视频直播.采购第三方视频 ...

  4. MyDAL - .QueryListAsync() 使用

    索引: 目录索引 一.API 列表 .QueryListAsync() .QueryListAsync<M>() 如: .QueryListAsync<AgentInventoryR ...

  5. HBase单机模式部署

    1.上传&解压 2.设置环境变量 3.启用&检验 4.编辑hbase-env.sh 5.编辑hbase-site.xml 6.启动hbase 7.验证 8.启动hbase shell

  6. Python第十三天 django 1.6 导入模板 定义数据模型 访问数据库 GET和POST方法 SimpleCMDB项目 urllib模块 urllib2模块 httplib模块 django和web服务器整合 wsgi模块 gunicorn模块

    Python第十三天   django 1.6   导入模板   定义数据模型   访问数据库   GET和POST方法    SimpleCMDB项目   urllib模块   urllib2模块 ...

  7. rabbitmq之基本原理及搭建单机环境

    1.RabbitMQ基本原理 1.MQ全称Message Queue,是一种分布式应用程序的通信方法,是消费-生产者模型的典型代表,producer向消息队列中不断写入消息,而另一端consumer则 ...

  8. 关于Java 中跳出多重循环

    前言 环境:window10 JDK 1.8 应用场景:在多个for循环或while循环中,直接跳到最外层的循环外面,而不是需要层层退出来. 使用: 使用一个标签label(也可以是其他单词,不能是关 ...

  9. pandas.DataFrame的pivot()和unstack()实现行转列

    示例: 有如下表需要进行行转列: 代码如下: # -*- coding:utf-8 -*- import pandas as pd import MySQLdb from warnings impor ...

  10. Status bar could not find cached time string image. Rendering in-process?

    在开发中,控制台经常输出“Status bar could not find cached time string image. Rendering in-process?” 在 Info.plist ...