歌名 - 歌手
0:00

    【宝藏】题解(五校联考3day1)

    分析

    如果打爆搜的话可以拿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;
    	}
    }
    
    posted @ 2018-05-08 15:37  无尽的蓝黄  阅读(140)  评论(0编辑  收藏  举报