Codeforces-629E Famil Door and Roads(期望)

版权声明:我这种蒟蒻的文章,真正的大佬一般看不上的_(:з」∠)_ https://blog.csdn.net/Paulliant/article/details/82711029

题意

给定一棵 n 个节点的树, m 个询问,每一个询问包含两个参数 a , b ,我们能够通过加一条边使 a , b 处于同一个环内。对于每一个询问,求这样的环的期望长度。
1 n , m 10 5

思路

细节比较多的一道题。首先我们可以用期望的线性性质,把环的期望拆成多个值,假设边连接 x , y ,形成 x a b y x 这样的环。那么 E [ ] = E [ ( x , a ) ] + E [ ( y , b ) ] + ( a , b ) + 1
不难发现,需要分类讨论,分 x , y 有无祖宗关系。
假如没有祖宗关系,那 x , y 只能分别在 a , b 的子树中出现,我们可以维护一个 s u m 1 数组, s u m 1 u 表示 u 的子节点到 u 的距离总和。 E [ ( x , a ) ] = s u m 1 a s z a , E [ ( y , b ) ] = s u m 1 b s z b
而若有祖宗关系,假设 a 节点更深,那么仍有 E [ ( x , a ) ] = s u m 1 a s z a ,而 y 则可以选择除 j m p ( a , d e p a d e p b 1 ) (设它为 z ) 这棵子树外的所有节点,那我们方便起见,可以先预处理一个节点到其它所有节点的距离之和 s u m 2 E [ ( y , b ) ] 只用将 s u m 2 b 减去 ( s u m 1 z + s z z ) , 即 b 到子树 z 中节点的距离总和,再除以 n s z z 即可。

代码

#include<bits/stdc++.h>
#define FOR(i,x,y) for(register int i=(x);i<=(y);++i)
#define DOR(i,x,y) for(register int i=(x);i>=(y);--i)
#define N 100003
typedef long long LL;
using namespace std;
template<const int maxn,const int maxm>struct Linked_list
{
    int head[maxn],to[maxm],nxt[maxm],tot;
    void clear(){memset(head,-1,sizeof(head));tot=0;}
    void add(int u,int v){to[++tot]=v,nxt[tot]=head[u],head[u]=tot;}
    #define EOR(i,G,u) for(register int i=G.head[u];~i;i=G.nxt[i])
};
Linked_list<N,N<<1>G;
int dfn[N],dep[N],fa[N],sz[N],son[N],top[N],ori[N],ord;
LL sum1[N],sum2[N];
int n,m;
LL gcd(LL x,LL y){return y?gcd(y,x%y):x;}

void dfs(int u,int f,int d)
{
    dep[u]=d,fa[u]=f,sz[u]=1,son[u]=0,sum1[u]=0;
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(v==f)continue;
        dfs(v,u,d+1);
        sum1[u]+=sum1[v]+sz[v];
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]])son[u]=v;
    }
}
void make_path(int u,int f,int tp)
{
    dfn[u]=++ord,ori[ord]=u,top[u]=tp;
    if(son[u])make_path(son[u],u,tp);
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(v==f||v==son[u])continue;
        make_path(v,u,v);
    }
}
int jmp(int x,int d)
{
    while(dep[x]-dep[fa[top[x]]]<=d)
    {
        d-=dep[x]-dep[fa[top[x]]];
        x=fa[top[x]];
    }
    return ori[dfn[x]-d];
}
int LCA(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
        else y=fa[top[y]];
    }
    return dep[x]<dep[y]?x:y;
}
void redfs(int u,int f,LL cur)
{
    sum2[u]=cur;
    EOR(i,G,u)
    {
        int v=G.to[i];
        if(v==f)continue;
        redfs(v,u,cur-sz[v]+(n-sz[v]));
    }
}

int main()
{
    G.clear();
    scanf("%d%d",&n,&m);
    FOR(i,1,n-1)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        G.add(u,v),G.add(v,u);
    }
    dfs(1,0,1);
    ord=0;make_path(1,0,1);
    redfs(1,0,sum1[1]);
    while(m--)
    {
        int x,y,z,lca;
        LL p1,p2,q1,q2,p,q;
        scanf("%d%d",&x,&y);
        if(dep[x]<dep[y])swap(x,y);
        lca=LCA(x,y);
        p1=sum1[x],q1=sz[x];
        if(lca==y)
        {
            z=jmp(x,dep[x]-dep[y]-1);
            p2=sum2[y]-sum1[z]-sz[z],q2=n-sz[z];
        }
        else p2=sum1[y],q2=sz[y];
        p=q1*q2*(dep[x]+dep[y]-2*dep[lca]+1)+p1*q2+p2*q1;
        q=q1*q2;
        printf("%lld/%lld\n",p/gcd(p,q),q/gcd(p,q));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Paulliant/article/details/82711029