如果打爆搜的话可以拿60分。
首先知道期望是可以累加的,即i通过j去到k的期望,等于i去到j的期望加j去到k的期望。
所以令d[i]表示i的出度,F[i]表示从i到i的父亲的期望,G[i]表示i的父亲到i的期望,j表示i其中任意一个儿子,k表示i的父亲,l表示k其中任意一个儿子,e表示k的父亲。
很容易推出:

\[F[i]=\dfrac{1}{d[i]}+\dfrac{1}{d[i]}\sum(1+F[j]+F[i]) \]

\[G[i]=\dfrac{1}{d[k]}+\dfrac{1}{d[k]}(1+G[k]+G[i])+\dfrac{1}{d[k]}\sum(1+F[l]+G[i]) \]

简化后得

\[F[i]=\sum{F[j]}+d[i] \]

\[G[i]=G[k]+\sum{F[l]}+d[k] \]

然后分q次走,用倍增lca很容易算出vi到vi+1的期望,把期望累加就可以了。

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int d[600000],g[600000],f[600000],last[600000],next[600000],a[600000],dad[60000][50],deep[600000],fsum[600000],gsum[600000],m2[100];
int n,m,test,q,p,tot;
int bj(int x,int y)
{
	next[++tot]=last[x];
	last[x]=tot;
	a[tot]=y;
	d[x]++;
}
int dg(int x,int fa)
{
	deep[x]=deep[fa]+1;
	f[x]+=d[x];
	for(int i=last[x];i;i=next[i])
	{
		if(a[i]!=fa)
		{
			dg(a[i],x);
			f[x]+=f[a[i]];
		}
	}
}
int dg1(int x,int fa)
{
	int allj=0;
	for(int i=last[x];i;i=next[i])
	{
		if(a[i]!=fa)
		{
			allj+=f[a[i]];
		}
	}
	for(int i=last[x];i;i=next[i])
	{
		if(a[i]!=fa)
		{
			g[a[i]]=d[x]+g[x]+allj-f[a[i]];
		}
	}
	for(int i=last[x];i;i=next[i])
	{
		if(a[i]!=fa)
		{
			dg1(a[i],x);
		}
	}
}
int dg2(int x,int fa)
{
	dad[x][0]=fa;
	fsum[x]=fsum[fa]+f[x];
	gsum[x]=gsum[fa]+g[x];
	for(int i=last[x];i;i=next[i])
	{
		if(a[i]!=fa)
			dg2(a[i],x);
	}
}
int work(int x,int y,int z)
{
	return fsum[x]-fsum[z]+gsum[y]-gsum[z];
}
int lca(int x,int y)
{
	if(x==y) return 0;
	int l=0;
	if(deep[x]<deep[y])
	{
		l=x;
		x=y;
		y=l;
		l=10000000;
	}
	int i,xx=x,yy=y,j;
	if(deep[xx]>deep[yy])
	{
		j=int(log2(deep[xx]));
		for(i=j;i>=0;i--)
		{
			if(deep[dad[xx][i]]>deep[yy])
			{
				xx=dad[xx][i];
			}
		}
		xx=dad[xx][0];
	}
	if(xx==yy)
	{
		if(l==0) return work(x,y,xx);
		else return work(y,x,xx);
	}
	j=int(log2(deep[xx]));
    for(i=j;i>=0;i--)
	{
        if (dad[xx][i]!=dad[yy][i])
		{
            xx=dad[xx][i];
            yy=dad[yy][i];
        }
    }
    xx=dad[xx][0];
    if(l==0) return work(x,y,xx);
		else return work(y,x,xx);
}
int main()
{
	int i,j,k,l,x,y;
	m2[0]=1;
	for(i=1;i<=20;i++)
		m2[i]=m2[i-1]*2;
	scanf("%d",&test);
	while(test--)
	{	
		scanf("%d",&n);
		tot=0;
		memset(d,0,sizeof(d));
		memset(g,0,sizeof(g));
		memset(f,0,sizeof(f));
		memset(a,0,sizeof(a));
		memset(last,0,sizeof(last));
		memset(next,0,sizeof(next));
		memset(dad,0,sizeof(dad));
		memset(deep,0,sizeof(deep));
		memset(fsum,0,sizeof(fsum));
		memset(gsum,0,sizeof(gsum));
		for(i=1;i<=n-1;i++)
		{
			scanf("%d%d",&x,&y);
			bj(x,y);
			bj(y,x);
		}
		deep[0]=0;
		dg(0,0);
		dg1(0,0);
		dg2(0,0);
		for(j=1;j<=int(log2(n));j++)
		{
			for(i=1;i<=n;i++)
			{
				dad[i][j]=dad[dad[i][j-1]][j-1];
			}
		}
		scanf("%d",&q);
		for(i=1;i<=q;i++)
		{
			int ans=0;
			scanf("%d%d",&p,&x);
			for(j=1;j<=p;j++)
			{
				scanf("%d",&y);
				ans+=lca(x,y);
				x=y;
			}
			printf("%d.0000\n",ans);
		}
		cout<<endl;
	}
}

相关文章: