【宝藏】题解(五校联考3day1)
2016-04-01 11:32
323 查看
分析
如果打爆搜的话可以拿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]=1d[i]+1d[i]∑(1+F[j]+F[i])
G[i]=1d[k]+1d[k](1+G[k]+G[i])+1d[k]∑(1+F[l]+G[i])
简化后得
F[i]=∑F[j]+d[i]
G[i]=G[k]+∑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; } }
相关文章推荐
- getClientRects 和 getBoundingClientRect 的用法和区别
- 如何在三个月内获得三年的工作经验(转载)
- 《开源安全运维平台-OSSIM最佳实践》喜获清华、北大、国家图书馆等国内一流大学图书馆收藏
- iOS 开发: 用户名、邮箱、电话号码、密码、昵称正则表达式验证
- js 排序
- Android Dalvik虚拟机初识
- Install Seafile Secure Cloud Storage on CentOS 7
- codeblocks 控制台一闪而过
- Android--Service完全解析,关于服务你所需知道的一切(上)
- HttpClient的一些参数设置(想到线程的朋友进)
- 选择排序SelectSort
- codeblocks 控制台一闪而过
- 《构建之法》第4章读后感
- 将war包部署到服务器的详细步骤
- jquery中attr和prop的区别
- oracle新建监听问题
- How to get API key (APPID)
- Eclipse打开项目后发生错误: The import javax.servlet cannot be resolved
- Gradle Android 多渠道打包
- hdu 4252(单调栈)