jzoj 4890. 【NOIP2016提高A组集训第14场11.12】随机游走 树上期望dp

来源:互联网 发布:java环境变量一键配置 编辑:程序博客网 时间:2024/05/16 05:38

题意

给出一棵树,每条边的长度为1,。若现在位于节点i,则每次都会等概率地走向与i相邻的点。问在所有的点对(i,j)中,从i走到j的最大期望长度是多少。
n<=100000

分析

作为一个期望毒瘤,暴力什么的根本不会啊2333~~所以比赛的时候这题就爆蛋啦。

我们设f[i,j]表示现在在节点i走到节点j且满足i和j有边直接相连的期望长度。

可以得到f[i,j]=1d[i]+kik!=j1+f[k,i]+f[i,j]d[i] d[i]表示i的度数

化简一下可得f[i,j]=d[i]+kik!=jf[k,i]

显然当 d[i]=1,即 i 为叶子时,f[i,j]=1. 于是设 1 为根,跑一遍 DFS,自下而上计算出所有的 f[i,fa[i]],fa[i]表示 i 的父亲。

机智的我们又可以观察到f[i,fa[i]]=jid[j]=size[i]21

那么很显然f[i,fa[i]]+f[fa[i],i]=n22

那么我们就可以顺便推出f[i,fa[i]]

那么我们就可以求出a[x]表示x到x的子树内的最大期望距离,b[x]表示x的子树内到x的最大期望距离,然后按照顺序把x的子树到x的距离排好,然后维护一个前缀max和后缀max就可以在O(d[x])的复杂度内得到答案了。

代码

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define N 100005using namespace std;int n,last[N],d[N],f[N],g[N],a[N],b[N],c[N],mx1[N],mx2[N],cnt,ans;struct edge{int to,next;}e[N*2];void addedge(int u,int v){    e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;    e[++cnt].to=u;e[cnt].next=last[v];last[v]=cnt;}void dfs(int x,int fa){    f[x]=d[x];    for (int i=last[x];i;i=e[i].next)    {        if (e[i].to==fa) continue;        dfs(e[i].to,x);        f[x]+=f[e[i].to];        a[x]=max(a[x],a[e[i].to]+g[e[i].to]);        b[x]=max(b[x],b[e[i].to]+f[e[i].to]);    }    int s=0;    for (int i=last[x];i;i=e[i].next)        c[++s]=a[e[i].to]+g[e[i].to];    mx1[0]=mx2[s+1]=0;    for (int i=1;i<=s;i++)        mx1[i]=max(mx1[i-1],c[i]);    for (int i=s;i>=1;i--)        mx2[i]=max(mx2[i+1],c[i]);    int s1=0;    for (int i=last[x];i;i=e[i].next)    {        if (e[i].to==fa) continue;        s1++;        ans=max(ans,b[e[i].to]+f[e[i].to]+max(mx1[s1-1],mx2[s1+1]));    }    g[x]=n*2-2-f[x];}int main(){    freopen("rw.in","r",stdin);freopen("rw.out","w",stdout);    scanf("%d",&n);    for (int i=1;i<n;i++)    {        int x,y;        scanf("%d%d",&x,&y);        addedge(x,y);        d[x]++;d[y]++;    }    dfs(1,0);    printf("%d.00000",ans);    return 0;}
0 0
原创粉丝点击