题意:给你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. Web前端新学

    本人大学时学的是网络工程,那时候只是大概学了一点HTML和CSS.毕业后没有找IT方面的工作,所以对专业知识忘得差不多了.然由于生活现状,终是决心重新好好学习IT,刚入学的一周学习了C#语言的一些知识 ...

  2. 模板引擎artTemplate的使用

    1.引入template文件 <script src = js/template-native.js></script> 2.写模板 <script type=" ...

  3. Git安装教程(windows)

    Git是当今最流行的版本控制软件,它包含了许多高级工具,这里小编就讲一下Git的安装. 下载地址:https://git-scm.com/downloads 首先如下图:(点击next) 第二步:文件 ...

  4. OpenCL——把vector变成scalar

    https://stackoverflow.com/questions/46556471/how-may-i-convert-cast-scalar-to-vector-and-vice-versa- ...

  5. Ubuntu16.04下搭建mysql + uwsgi + nginx环境启动flask 项目

    1.安装mysql Sudo apt-get install mysql 配置mysql的数据存储路径,默认在 /var/lib/mysql sudo cp -R /var/lib/mysql/* / ...

  6. VR一体机如何退出FFBM

            Fast Factory Boot Mode(FFBM)是一种半开机的模式,它的主要目的是方便工厂测试,提高生产效率.正常情况下终端用户是不会碰到的.但售后的同学最近连续收到几台客户退 ...

  7. DataPipeline |《Apache Kafka实战》作者胡夕:Apache Kafka监控与调优

    胡夕 <Apache Kafka实战>作者,北航计算机硕士毕业,现任某互金公司计算平台总监,曾就职于IBM.搜狗.微博等公司.国内活跃的Kafka代码贡献者. 前言 虽然目前Apache ...

  8. C#枚举(Enum)小结

    枚举概念 枚举类型(也称为枚举)提供了一种有效的方式来定义可能分配给变量的一组已命名整数常量.该类型使用enum关键字声明. 示例代码1 enum Day { Sunday, Monday, Tues ...

  9. 海思uboot启动流程详细分析(三)【转】

    1. 前言 书接上文(u-boot启动流程分析(二)_平台相关部分),本文介绍u-boot启动流程中和具体版型(board)有关的部分,也即board_init_f/board_init_r所代表的. ...

  10. java拦截器(interceptor)

    1.声明式 (1)注解,使用Aspect的@Aspect (2)实现HandlerInterceptor /** * 拦截请求 * * @author Administrator * */ @Comp ...