• 【宝藏】题解(五校联考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
    ",ans);
    		}
    		cout<<endl;
    	}
    }
    
  • 相关阅读:
    博客新域名www.tecchen.tech
    [转载]Redis 持久化之RDB和AOF
    基于zookeeper集群的云平台-配置中心的功能设计
    22部漫威电影大合集和观影顺序
    类的嵌套定义、使用以及用头文件实现多个文件编程(匠心之作C++ p105 22 )
    Python的print格式
    Tensorflow2.0+Anaconda + Windows10+cuda10.0+python(转自豌豆代理)
    C语言中用scanf连续输入两个字符类型的问题(转)
    算法和流程图(及N-S流程图)
    git的安装及针对码云的操作(二)
  • 原文地址:https://www.cnblogs.com/chen1352/p/9008547.html
Copyright © 2020-2023  润新知