51nod 1803 森林的直径

来源:互联网 发布:话费充值系统源码 编辑:程序博客网 时间:2024/06/05 14:45

链接:
https://www.51nod.com/onlineJudge/questionCode.html#problemId=1803&noticeId=396652

树是随机生成的。

就题目的代码设计思路不会很复杂。但问题是树的深度较坏情况的概率。我们是需要分析好的。

也就是说,我们需要明白随机生成一棵树的期望深度是多少。出现稍微坏一点的可能又是多少。

题目中生成树的方式可以生成任何一种形状的n节点树。

这是因为树也是DAG图.任何形状的树,都可以拓扑排序后重新标号。

我们计算这种方式生成的树的期望深度。其实就是随机生成一棵树的期望深度。

但是平均不代表不能代表特殊。

更具体来说,对于n个节点的随机树。最大深度超过h时候大概率是多少?(是否有绝对的概率优势)。

这里只能给出平均意义下的树的深度。出现教坏情况的概率应该不会很大。

首先。第n个结点可能深度是多少呢?

算法可以看作我们从节点n开始.每次随机的选择一个之前的节点。去跳跃。每次跳跃距离都不超过到达节点1的距离的一半概率近似为O(12)

连续k次跳跃。出现这种情况的概率显然随着k的增加收敛很快。O((12)k)。但这个分析很不严谨。能力有限。不能给出准确的概率分布。

但可以看出。出现坏的情况的概率不会很大。

那么平均意义下的结论还是值得使用的。

定义。节点n的平均深度为 f(n)

则:
f(n)=1n1k=1n1(f(k)+1)=1+1n1k=1n1f(k)

则:
f(n)(n1)=(n1)+k=1n1f(k)f(n1)(n2)=(n2)+k=1n2f(k)

所以:
f(n)(n1)f(n1)(n2)=1+f(n1)f(n)(n1)=f(n1)(n1)+1f(n)=f(n1)+1n1

所以:
f(n)=Hn1,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(l1,r)

定义dp[i][k]表示:以从i开始。最小的使得s(l,r)kr

定义:q(P,l,r)表示从P出发。只使用[l,r]的边的最长路径。

定义len[P][k]表示:以点P为出发点。最小的使得q(P,i,r)kr

考虑左侧加入一条边时。新加入的边的起点产生的影响:

只可能与其兄弟之间产生了化学变化( - - ! )

而新加入边后更新了父节点的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;}
原创粉丝点击