bzoj 3244: Noi2013树的计数
2016-07-29 16:07
344 查看
题目大意就是给出dfs序和bfs序,求树的期望高度
首先感谢Mektpoy的blog:树的计数——Mektpoy
Mektpoy的做法是O(nlogn)的,已经讲得比较清楚了,但还是看了好久才想清楚,所以多说两句。
1.当pos[B] = pos[A] + 1时,若B是A的儿子,因为bfs序相邻,那么B必须是A的下一层的第一个儿子,所以在这层之前不可能出现过bfs大于B的,即在此之前的dfs序中不能出现比B大的数,还是一个RMQ问题。
2.因为懒得写线段树了,就用st表来求RMQ。Mektpoy说的:"对于dfs序在B后面的点 对于任意一个这些点中bfs序>B的点 他前面(也就是B和这个点之间)若有一个 < A的点也不可以",只需求出最后一个比B大的数就能满足任意了,这里利用st表来递归O(logN)的求出最后一个比B大的数,再求之间最小的数,与A比较即可。
好像还有O(N)的算法,应该是利用更巧妙的性质,懒得看了(好渣)
首先感谢Mektpoy的blog:树的计数——Mektpoy
Mektpoy的做法是O(nlogn)的,已经讲得比较清楚了,但还是看了好久才想清楚,所以多说两句。
1.当pos[B] = pos[A] + 1时,若B是A的儿子,因为bfs序相邻,那么B必须是A的下一层的第一个儿子,所以在这层之前不可能出现过bfs大于B的,即在此之前的dfs序中不能出现比B大的数,还是一个RMQ问题。
2.因为懒得写线段树了,就用st表来求RMQ。Mektpoy说的:"对于dfs序在B后面的点 对于任意一个这些点中bfs序>B的点 他前面(也就是B和这个点之间)若有一个 < A的点也不可以",只需求出最后一个比B大的数就能满足任意了,这里利用st表来递归O(logN)的求出最后一个比B大的数,再求之间最小的数,与A比较即可。
好像还有O(N)的算法,应该是利用更巧妙的性质,懒得看了(好渣)
/************************************************************** Problem: 3244 User: cabinfever Language: C++ Result: Accepted Time:1016 ms Memory:35676 kb ****************************************************************/ #include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <algorithm> #include <iostream> #include <cstring> using namespace std; int dfs[200010]; int bfs[200010]; int haha[200010]; int pos[200010]; int n; int st_max[200010][20]; int st_min[200010][20]; double ans = 0; int find_b(int i,int j,int x) { if(j == i) return j; int k = log2(j - i); if(st_max[j + 1 - (1 << k)][k] > x) return find_b(j+1-(1<<k),j,x); if(st_max[i][k] > x) return find_b(i,i+(1<<k)-1,x); return i; } int main() { cin >> n; for(int i = 1; i <= n; i++) scanf("%d",&dfs[i]); for(int i = 1; i <= n; i++) scanf("%d",&bfs[i]); for(int i = 1; i <= n; i++) { haha[bfs[i]] = i; bfs[i] = i; } for(int i = 1; i <= n; i++) { dfs[i] = haha[dfs[i]]; pos[dfs[i]] = i; } ans = 2; for(int i = 1; i <= n; i++) { st_min[i][0] = dfs[i]; st_max[i][0] = dfs[i]; } int k = log2(n) + 1; for(int j = 1; j < k; j++) for(int i = 1; i <= n; i++) if(i + (1 << j) <= n + 1) { st_min[i][j] = min(st_min[i][j-1],st_min[i + (1 << (j-1))][j-1]); st_max[i][j] = max(st_max[i][j-1],st_max[i + (1 << (j-1))][j-1]); } for(int i = 2; i < n; i++) { if(pos[i] > pos[i+1]) ans++; else if(pos[i+1] > pos[i]+1) ans += 0; else { int j = find_b(pos[i+1],n,i+1); int k = log2(j - pos[i+1] + 1); int k2 = log2(pos[i]-1); int max2 = max(st_max[1][k2],st_max[pos[i] + 1 - (1 << k2)][k2]); if(min(st_min[pos[i+1]][k],st_min[j-(1<<k)+1][k]) < i || max2 > i + 1) ans += 0; else ans += 0.5; } } printf("%.3lf\n",(double)ans-0.001); printf("%.3lf\n",(double)ans); printf("%.3lf\n",(double)ans+0.001); return 0; }
相关文章推荐
- 书评:《算法之美( Algorithms to Live By )》
- 动易2006序列号破解算法公布
- C#递归算法之分而治之策略
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- C#算法之大牛生小牛的问题高效解决方法
- C#算法函数:获取一个字符串中的最大长度的数字
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- 经典排序算法之冒泡排序(Bubble sort)代码
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法