HDU 5449 Robot Dog ACM/ICPC 2015 Changchun Online(数学期望+LCA)

来源:互联网 发布:网络信息安全 电子书 编辑:程序博客网 时间:2024/06/06 16:58

Robot Dog

Time Limit: 3000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 351    Accepted Submission(s): 106

Problem Description

Mike has just found a dungeon. Inside there are n rooms and p treasure chests. Chests1,...,p are located in room v1,...,vp respectively. The rooms are connected by n1 passages. Any two rooms connected by a passage are considered adjacent. This dungeon is very special that there exists a path between any two rooms. Among these treasure chests, only chest 1 can be taken in the very beginning, others must be taken in order. That is, only after chest i is taken, may chest i+1 be taken as well, for every i{1,...,p1}.
Mike is lazy, so he dislikes to explore the dungeon on his own feet. Therefore, Mike sends his robot dog, Blot, to collect the treasures in the dungeon. Blot can automatically collect the treasures from the chests, and it takes Blot exactly a second to move to any adjacent room. However, Blot’s movement is uncontrollable. Blot moves to all adjacent rooms with the same probability. For example, if there arek adjacent rooms, then Blot will move to any of them with probability 1k. Please help mike to compute the expected time that Blot collects all p treasures for him.

Input

The first line on the input contains an integer T(T10). There will be T test cases. The first line of each test case contains an integer n(2n50000) indicating the number of rooms in the dungeon. The rooms are numbered from 0 to n1. Each of the following n1 lines contains two integers u and v(u,v{0,...,n1}) indicating room u and room v are adjacent.
The next line contains an integer q(q100) indicating the number of scenarios. Each of the following q lines represents a scenario which consists of some integers p,v0,v1,...,vp separated by blanks. The first integer p(0<p500) indicates there will be p treasure chests. The second integer v0 indicates that Blot is in room v0 at the beginning. For i{1,...,p}, the ith treasure will be spawn at room vi. You may assume vi vi-1 for every i{1,...,p}.

Output

For each test case, output q lines, and the jth of them corresponds to the jth scenario of the test case. For each scenario, output the expected time in seconds such that Blot collects all treasures. Print the answer to the fourth decimal place, and separate two consecutive test cases with a blank line.

Sample Input

231 01 221 0 12 0 2 140 12 03 013 0 1 0 1

Sample Output

1.00005.000011.0000

Source

2015 ACM/ICPC Asia Regional Changchun Online



        大致题意是,给你一棵n个节点的树,树上有k个宝石,编号0~k-1,现在从起点s放一条电子狗,电子狗在每个节点往各邻接点走的概率相同,问电子狗按编号顺序拿完所有宝石的期望步数。

        这题的关键就是如何考虑这个期望步数,因为如果没有一个好的考虑方式,一直在乱走,情况很多无法求出期望。所以我们考虑,对于从一个点u到一个点v的期望步数,肯定与lca有关,大致可以分为,从u到lca的期望步数,再从lca到v的期望步数,两者之后即为答案。再进一步思考发现从父亲往儿子走和从儿子往父亲走是两种不同的情况。于是考虑设置up数组和down数组,分别表示从该点到根的期望步数和从根到该点的期望步数。如此一来我们的ans=up[u]-up[lca]+down[v]-down[lca]。现在的问题就是如何求这个up和down数组。

        我们考虑先求单个的u数组和d数组,分别表示从该点往上到它的父亲的期望步数,和父亲到该点的期望步数,之后对这两个进行累加就能得到up和down数组。首先,我们考虑u数组,从i点往上到父亲有两种情况,一是直接往上走一步到父亲fa,二是先走到i的某个儿子,再从儿子到i再到fa,于是可以写成下面的形式,其中son[i]表示i的儿子个数:

                                                                          

        然后,当i为叶子节点的时候,u[i]=1,又son[i]+1=size[i],所以u[i]=2*size[i]-1。相当于只需要知道size数组就可以求出u数组。接下来我们看d数组,情况看似比较复杂,其实我们可以转换一下,我们知道u是从儿子到父亲,而d是父亲到儿子。那么,如果我们强行把这棵树反转过来会怎样呢?儿子变成了父亲,父亲变成了儿子,u数组变成了d数组,d数组变成了u数组。这意味这什么,意味着d[i]也满足u[i]表达式的形式,只不过由于反转,原本是size[i]就会变成(n-size[i]),相当于是翻转过来i点的size。于是就有d[i]=2*(n-size[i])+1。

        求得了u和d数组,我们就可以知道up和down数组,这之后对于一个拿宝石的顺序,我们只需要对相邻两点求lca,然后按照之前说的式子计算即可,然后注意up和down数组要用LL。具体见代码:

#include<bits/stdc++.h>#define LL long long#define INF 0x3f3f3f3f#define N 101000using namespace std;vector<int> g[N];LL up[N],down[N];int n,size[N];namespace LCA{    int dp[N][20],dep[N];    inline void dfs(int x,int fa)    {        for(int i=0;i<g[x].size();i++)        {            int y=g[x][i];            if (y==fa) continue;            dep[y]=dep[x]+1;            dp[y][0]=x; dfs(y,x);        }    }    void ST()    {        for(int j=0;j<17;j++)            for(int i=1;i<=n;i++)                dp[i][j+1]=dp[dp[i][j]][j];    }    inline int lca(int u,int v)    {        if (u==v) return u;        if (dep[v]>dep[u]) swap(u,v);        for(int i=18;i>=0;i--)            if (dep[dp[u][i]]>=dep[v]) u=dp[u][i];        if (u==v) return u;        for(int i=18;i>=0;i--)            if (dp[u][i]!=dp[v][i]) u=dp[u][i],v=dp[v][i];        return dp[u][0];    }}void getsize(int x,int fa){    size[x]=1;    for(int i=0;i<g[x].size();i++)    {        int y=g[x][i];        if (y==fa) continue;        getsize(y,x); size[x]+=size[y];    }}void dfs(int x,int fa){    if (fa!=-1)    {        up[x]=up[fa]+2LL*size[x]-1LL;        down[x]=down[fa]+2LL*(n-size[x])-1LL;    }    for(int i=0;i<g[x].size();i++)    {        int y=g[x][i];        if (y==fa) continue;        dfs(y,x);    }}void init(){    memset(g,0,sizeof(g));    memset(up,0,sizeof(up));    memset(down,0,sizeof(down));    memset(size,0,sizeof(size));}int main(){    int T_T;    cin>>T_T;    while(T_T--)    {        init();        scanf("%d",&n);        for(int i=1;i<n;i++)        {            int u,v;            scanf("%d%d",&u,&v);            g[u].push_back(v);            g[v].push_back(u);        }        LCA::dfs(0,-1);LCA::ST();        getsize(0,-1); dfs(0,-1);        int q; scanf("%d",&q);        while(q--)        {            LL ans=0;            int k,u,v;            scanf("%d%d",&k,&u);            while(k--)            {                int v; scanf("%d",&v);                int lca=LCA::lca(u,v);                ans+=up[u]-up[lca]+down[v]-down[lca];                u=v;            }            printf("%I64d.0000\n",ans);        }        if (T_T) puts("");    }}


阅读全文
0 0
原创粉丝点击