JZOJ 4225. 【五校联考3day1】宝藏
题目
Description
Input
Output
Sample Input
2
3
1 0
1 2
2
1 0 1
2 0 2 1
4
0 1
2 0
3 0
1
3 0 1 0 1
Sample Output
1.0000
5.0000
<空行>
11.0000
Data Constraint
题解
-
这是一个树上随机游走的问题。
-
题目可以简化为:从一个节点出发,等概率地向它所连的点走去,每条边权均为。求从起点按顺序经过的一系列节点后到达终点的期望路径长度。
-
首先我们把问题中的路线拆分为以下两种:
-
1、表示从走向,记录表示其期望路径长度;
-
2、表示从走向,记录表示其期望路径长度。
-
问题中的路径就是若干条上面两种的路径总和,总的期望值也就是每一段的期望值总和。
-
现在考虑怎么计算和?
-
先令表示的度数,表示的子节点集合。
-
计算的方程如下:
-
可以直接走到,也可以经过它的儿子再走到。
-
计算的方程如下:
-
可以直接走到,也可以先走到,也可能走到的兄弟。
-
于是这样就可以把所有的和计算出来了。
-
记得其中.
-
如果一步一步地走,会时间超限,
-
自然想到用倍增.
代码
#include<cstdio>
#include<cstring>
using namespace std;
int last[50010],next[100010],tov[100010],len=0;
int deep[50010],deg[50010];
int f[50010],g[50010],e[17],tn;
struct node
{
int f,g,to;
}q[50010][17];
void add(int x,int y)
{
tov[++len]=y;
next[len]=last[x];
last[x]=len;
}
void dfs(int x,int fa)
{
f[x]=deg[x];
for(int i=last[x];i;i=next[i]) if(tov[i]!=fa)
{
deep[tov[i]]=deep[x]+1;
dfs(tov[i],x);
f[x]+=f[tov[i]];
}
}
void dfs1(int x,int sum,int fa)
{
if(x>1) g[x]=g[fa]+deg[fa]+sum-f[x];
int ss=0;
for(int i=last[x];i;i=next[i]) if(tov[i]!=fa) ss+=f[tov[i]];
for(int i=last[x];i;i=next[i]) if(tov[i]!=fa) dfs1(tov[i],ss,x);
}
void dfs2(int x,int fa)
{
q[x][0].to=fa,q[x][0].f=f[x],q[x][0].g=g[x];
for(int i=1;i<=16;i++)
{
q[x][i].to=q[q[x][i-1].to][i-1].to;
q[x][i].f=q[x][i-1].f+q[q[x][i-1].to][i-1].f;
q[x][i].g=q[x][i-1].g+q[q[x][i-1].to][i-1].g;
}
for(int i=last[x];i;i=next[i]) if(tov[i]!=fa) dfs2(tov[i],x);
}
int main()
{
int n,i,j,k,x,y,qs,p;
scanf("%d",&tn);
e[0]=1;
for(i=1;i<=16;i++) e[i]=e[i-1]*2;
while(tn--)
{
scanf("%d",&n);
memset(last,0,sizeof(last));
memset(deg,0,sizeof(deg));
len=0;
for(i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
x++,y++;
deg[x]++,deg[y]++;
add(x,y);add(y,x);
}
deep[1]=0;
memset(g,0,sizeof(g));
memset(f,0,sizeof(f));
dfs(1,0);
dfs1(1,0,0);
dfs2(1,0);
scanf("%d",&qs);
for(i=1;i<=qs;i++)
{
scanf("%d",&p);
int la,no;
scanf("%d",&la);
la++;
int ans=0;
for(j=2;j<=p+1;j++)
{
scanf("%d",&no);
no++;
x=la,y=no;
if(deep[x]>deep[y])
{
for(k=16;k>=0;k--) if(deep[x]-e[k]>=deep[y])
{
ans+=q[x][k].f;
x=q[x][k].to;
}
}
else
{
for(k=16;k>=0;k--) if(deep[y]-e[k]>=deep[x])
{
ans+=q[y][k].g;
y=q[y][k].to;
}
}
if(x!=y)
{
for(k=16;k>=0;k--) if(q[x][k].to!=q[y][k].to)
{
ans+=q[x][k].f+q[y][k].g;
x=q[x][k].to;
y=q[y][k].to;
}
ans+=q[x][0].f+q[y][0].g;
}
la=no;
}
printf("%d.0000\n",ans);
}
printf("\n");
}
fclose(stdin);
fclose(stdout);
return 0;
}