[树形DP][概率期望]JZOJ 4225 宝藏
分析
// 赤い面 // 赤い仮面 // 白 色围 巾 // 手 强化筋肉 手 // 手 强化筋肉 手 // 手 强化筋肉 手 // 双重飓风 //山 腿 腿 //山山 腿 腿 //山山 腿 腿 //山山山 脚 脚 //山山山山管钢管钢管钢管钢管钢管钢管钢管钢管 // 你妈的,为甚麽 #include <iostream> #include <cstdio> #include <memory.h> using namespace std; const int N=5e4+10; struct Edge { int u,v,nx; }g[2*N]; int cnt,list[N]; int T,n,q; int f1[N],f2[N],deg[N],d[N],f[N][20]; void Add(int u,int v) {g[++cnt]=(Edge){u,v,list[u]};list[u]=cnt;deg[u]++;} void DFS1(int u,int fa) { f1[u]=deg[u]; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) DFS1(g[i].v,u),f1[u]+=f1[g[i].v]; } void DFS2(int u,int fa) { int sum=deg[u]; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) sum+=f1[g[i].v]; else sum+=f2[u]; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) f2[g[i].v]=sum-f1[g[i].v],DFS2(g[i].v,u); } void Build(int u,int fa) { d[u]=d[fa]+1;f[u][0]=fa; f1[u]+=f1[fa];f2[u]+=f2[fa]; for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) Build(g[i].v,u); } int Get_LCA(int a,int b) { if (d[a]<d[b]) swap(a,b); for (int i=19;i>=0;i--) if (d[f[a][i]]>=d[b]) a=f[a][i]; if (a==b) return a; for (int i=19;i>=0;i--) if (f[a][i]!=f[b][i]) a=f[a][i],b=f[b][i]; return f[a][0]; } int main() { for (scanf("%d",&T);T;T--) { scanf("%d",&n);cnt=0; memset(list,0,sizeof list); memset(f1,0,sizeof f1); memset(f2,0,sizeof f2); memset(f,0,sizeof f); memset(d,0,sizeof d); memset(deg,0,sizeof deg); for (int i=1,u,v;i<n;i++) scanf("%d%d",&u,&v),u++,v++,Add(u,v),Add(v,u); DFS1(1,0); f1[1]=f2[1]=0; DFS2(1,0); d[1]=1; Build(1,0); for (int j=1;j<=19;j++) for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; for (scanf("%d",&q);q;q--) { int p,x,y; double ans=0; scanf("%d",&p);p++; scanf("%d",&x);x++; for (int i=1;i<p;i++) { scanf("%d",&y);y++; int lca=Get_LCA(x,y); ans+=f1[x]-f1[lca]+f2[y]-f2[lca]; x=y; } printf("%.4lf\n",ans); } printf("\n"); } }
在日渐沉没的世界里,我发现了你。