Luo's oj P1895 树上游走期望(tree)

传送门

分析

首先可以模拟一下样例,好吧这是一个鬼畜的过程,数论?推公式QAQ我好想不会;树形dp,感觉是但是好像不太懂期望,不过好像要用lca();结果果断爆零。我果然还是太菜orz;当场弃疗;yrc大佬又抄了代码AK全场orz
还是讲一下题目首先就是建图,之后就是一个鬼畜的树形dp+期望,计算答案用lca()其实我不会令lca=lca(u,v),那么从u点到v点的期望步数就是up[u]-up[lca]+down[v]-down[lca]

首先我们约定up[i]表示 i–> fa[i] ;的期望步数**down[i]表示 fa[i]–>i 的期望值
son[i]表示 节点数
第一种情况 i 到 fa 的方法有两种,第一种是直接往上走到fa,第二种是先到i的某个儿子v,然后再从v到i到fa,故有
这里写图片描述
图片借用https://blog.csdn.net/v5zsq 大佬orz 此处up[]是u[]
fa到i的方法有三种,第一种是直接往下走到i,第二种是走到fa的父亲节点再走回到fa再走到i,第三种是走到i的某个兄弟节点v然后从v走到fa再走到i,故有
这里写图片描述 此处bro(i)=son(i)-1

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod=1000000007;
const int N=100010;
int head[N],Next[N<<1],vet[N<<1],tot,n,lg;
int d[N],pre[N][20];ll up[N],down[N];
void add(int x,int y){
    tot++;
    vet[tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
}//邻接表
void dfsf(int u,int fa){
    for(int i=head[u];i;i=Next[i]){
        int v=vet[i];
        if(v==fa)continue;
        dfsf(v,u);
        up[u]=(up[u]+up[v]+1)%mod;
    }
    up[u]=(up[u]+1)%mod;
}//产生up[]数组
void dfsg(int u,int fa){
    ll sum=0;
    for(int i=head[u];i;i=Next[i]){
        int v=vet[i];
        if(v==fa)sum=(sum+down[u]+1)%mod;
        else sum=(sum+up[v]+1)%mod;
    }
    for(int i=head[u];i;i=Next[i]){
        int v=vet[i];
        if(v==fa)continue;
        down[v]=((sum-up[v])%mod+mod)%mod;
        dfsg(v,u);
    }
}//产生down[]数组
void dfs(int u,int fa,int dep){
    d[u]=dep;pre[u][0]=fa;
    up[u]=(up[fa]+up[u])%mod;
    down[u]=(down[fa]+down[u])%mod;
    for(int i=head[u];i;i=Next[i]){
        int v=vet[i];
        if(v!=fa)dfs(v,u,dep+1);
    }
}//lca的预处理
int lca(int u,int v){
    if (d[u]<d[v])swap(u,v);
    int del=d[u]-d[v];
    if (del)
        for (int i=0;i<=lg&&del;i++,del>>=1)
            if(del&1)u=pre[u][i];
    if (u==v) return u;
    for (int i=lg;i>=0;i--)
        if (pre[u][i]!=pre[v][i]){
            u=pre[u][i];
            v=pre[v][i];
        }
    return pre[u][0];
}//lca基本操作
int main(){
    int Q;scanf("%d%d",&n,&Q);
    lg=log(n)/log(2)+1;//求出最大的2^lg的lg
    for(int i=1;i<n;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);add(y,x);
    }//构图
    dfsf(1,-1);
    up[1]=0;down[1]=0;
    dfsg(1,-1);
    dfs(1,-1,0);
    for(int i=1;i<=lg;i++)
        for(int j=1;j<=n;j++)
            pre[j][i]=pre[pre[j][i-1]][i-1];//lca预处理
    while(Q--){
        int u,v;
        scanf("%d%d",&u,&v);
        int _lca=lca(u,v);
        ll ans=(up[u]-up[_lca]+down[v]-down[_lca]+mod)%mod;//注意取模时的负数
        printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36316033/article/details/81208779
OJ