51nod 1803 森林的直径
来源:互联网 发布:话费充值系统源码 编辑:程序博客网 时间:2024/06/05 14:45
链接:
https://www.51nod.com/onlineJudge/questionCode.html#problemId=1803¬iceId=396652
树是随机生成的。
就题目的代码设计思路不会很复杂。但问题是树的深度较坏情况的概率。我们是需要分析好的。
也就是说,我们需要明白随机生成一棵树的期望深度是多少。出现稍微坏一点的可能又是多少。
题目中生成树的方式可以生成任何一种形状的n 节点树。
这是因为树也是DAG 图.任何形状的树,都可以拓扑排序后重新标号。
我们计算这种方式生成的树的期望深度。其实就是随机生成一棵树的期望深度。
但是平均不代表不能代表特殊。
更具体来说,对于n 个节点的随机树。最大深度超过h 时候大概率是多少?(是否有绝对的概率优势)。
这里只能给出平均意义下的树的深度。出现教坏情况的概率应该不会很大。
首先。第n 个结点可能深度是多少呢?
算法可以看作我们从节点n 开始.每次随机的选择一个之前的节点。去跳跃。每次跳跃距离都不超过到达节点1 的距离的一半概率近似为O(12)
连续k 次跳跃。出现这种情况的概率显然随着k 的增加收敛很快。O((12)k) 。但这个分析很不严谨。能力有限。不能给出准确的概率分布。
但可以看出。出现坏的情况的概率不会很大。
那么平均意义下的结论还是值得使用的。
定义。节点n 的平均深度为 f(n)
则:f(n)=1n−1∑k=1n−1(f(k)+1)=1+1n−1∑k=1n−1f(k)
则:f(n)(n−1)=(n−1)+∑k=1n−1f(k)f(n−1)(n−2)=(n−2)+∑k=1n−2f(k)
所以:f(n)(n−1)−f(n−1)(n−2)=1+f(n−1)f(n)(n−1)=f(n−1)(n−1)+1f(n)=f(n−1)+1n−1
所以:f(n)=Hn−1,n>1
特别的:f(1)=0
其中Hn=O(logen)
现在。我们就当作这是一个深度为O(log) 的树。
提供一种反向离线递推的方法:
对于问题。离线存储后。按照l 排序。
令s(l,r) 为:询问l,r 时对应的答案。
显然:s(l,r)≤s(l,r+1)s(l,r)≤s(l−1,r)
定义dp[i][k] 表示:以从i 开始。最小的使得s(l,r)≥k 的r
定义:q(P,l,r) 表示从P 出发。只使用[l,r] 的边的最长路径。
定义len[P][k] 表示:以点P 为出发点。最小的使得q(P,i,r)≥k 的r
考虑左侧加入一条边时。新加入的边的起点产生的影响:
只可能与其兄弟之间产生了化学变化( - - ! )
而新加入边后更新了父节点的len 需要O(log2n) 的时间。
所以总时间复杂度时 O(nlog2n)
始终想不明白题解的O(nlog n)
还有:此题输入数据量过大。建议使用分块读取。
下面是AC代码:
#include <algorithm>#include <stdio.h>#include <string.h>#include <cmath>#define MAXN 500005#define CHILD 1000using namespace std;const int INF=0x3f3f3f3f;struct Io{ char A[MAXN],*L,*R; Io() { L=R=A; } void Io_fread() { L=A; R=A+fread(A,sizeof(char),MAXN,stdin); } void read(int &tmp) { tmp=0; if(L==R) { Io_fread(); if(L==R)return; } while(*L<'0'||*L>'9') { L++; if(L==R) { Io_fread(); if(L==R)return; } } while(*L>='0'&&*L<='9') { tmp=tmp*10+*L-'0'; L++; if(L==R) { Io_fread(); if(L==R)return; } } }}I;struct prob{ int l,r; prob(){}; bool operator <(const prob&a)const { return l>a.l; }}Q[MAXN];int len[MAXN][61];int ph[MAXN];int dp[CHILD];int main (){ freopen("/Users/gaoxusheng/Desktop/In.txt","rw",stdin); int n,a,b,c=0,ans=0,q; I.read(n); for(int i=1;i<n;i++) { I.read(a); I.read(b); ph[b]=a; } I.read(q); for(int i=0;i<q;i++) { I.read(Q[i].l); I.read(Q[i].r); Q[i].l++; Q[i].r++; if(Q[i].l>n)Q[i].l=n; if(Q[i].r>n)Q[i].r=n; } sort(Q,Q+q); memset(len,0x3f,sizeof len); memset(dp,0x3f,sizeof dp); for(int d=n;d;d--) { int P=ph[d]; len[d][0]=d; len[P][0]=d; dp[1]=d; for(int k=0;len[d][k]<INF;k++) for(int t=0;len[P][t]<INF;t++) { int u; if(len[d][k]>len[P][t]) u=len[d][k]; else u=len[P][t]; if(dp[k+t+1]>u)dp[k+t+1]=u; } for(int k=0;len[d][k]<INF;k++) if(len[P][k+1]>len[d][k]) len[P][k+1]=len[d][k]; while(c<q&&Q[c].l>=d) { int u=0; for(int k=1;dp[k]<=Q[c].r;k++)u=k; ans+=u; c++; } } printf("%d\n",ans); return 0;}
阅读全文
1 0
- 51nod 1803 森林的直径
- 51Nod-1803-森林直径
- 51nod 1766 线段树维护树的直径
- bzoj3124 [Sdoi2013]直径 树的直径
- 【树的直径】
- 树的直径
- 求树的直径
- 树的最长直径
- HDU4607 树的直径
- URAL1056(树的直径)
- 树的直径hdu3721
- 树的直径
- 树的直径
- 树的重心、直径
- 求解一棵树的直径
- 树的直径
- 树的直径 【总结】
- poj1985 树的直径
- jQ2 强大的选择器
- MATLAB2013在2017年10月份之后就不能激活了
- MakeFile基础知识&多目录编译
- 【SDK接入】使用UnityPlugin接入Bugly(iOS)
- 【Scikit-Learn 中文文档】交叉验证
- 51nod 1803 森林的直径
- Poj2758 Checking the Text
- HOJ P2143 Song(贪心)
- android camera(二):摄像头工作原理、s5PV310 摄像头接口(CAMIF)
- 消息机制 钩子+回调
- Java学习课程七:编写程序
- java反射机制
- 统计学习三要素的思考
- jQ3 jQuery与DOM