标签:define 整数 i++ bit style tput col turn 说明
一棵n个节点的树,树上有k个宝石,编号1~k,现在从起点s放一条电子狗,电子狗在每个节点往各邻接点走的概率相同,问电子狗按编号顺序拿完所有宝石的期望步数
Input
第一行一整数T表示用例组数,每组用例首先输入一整数n表示点数,之后n-1行每行两个整数u和v表示u和v在树上有一条边,之后输入一整数q表示查询数,最后q行每行首先输入一个整数k表示宝石数量,然后输入一整数s表示电子狗起点,最后k个整数表示编号从1~k的宝石在树上的位置(T<=10,2<=n<=50000,q<=100,0<=k<=500)
Output
对于每次查询,输出电子狗按顺序拿完所有宝石的期望步数,相邻两组用例的输出用一空行隔开
肯定不能一次一次地去计算不同顺序的期望权值。
所以考虑从中找到规律
从父节点到子节点和从子节点到父节点的期望路径长度是不一样长的,要分开计算
用up[i]表示i到根节点的期望路径长,down[i]表示i到根的期望路径长
画个图可以发现 u->v的期望路径长ans=up[u]+down[v]-up[lca]-down[lca]
要直接算这两个数组很困难,考虑把问题细分,将i到父节点的长设为u[i],父节点到i的长设为d[i],把u[i]累加可得up[i],down[i]同理
从儿子走到父亲的期望长度,可以是直接走到父亲,也可能在到父亲和到儿子的路径中选,即先走到儿子再回父亲
u[i]=1+∑(u[v]+u[i])/(son[i]+1)
化简,得 u[i]*(son[i]+1)=1+∑ u[v] +son[i]*u[i] ---->u[i]=1+ ∑ u[v]
当i是叶节点的时候,只能往父亲走,期望长度就是1,即u[i]=1,又son[i]+1=siz[i]
所以一层层累上去,可得到 u[i]=2*siz[u]-1,说明可以通过siz直接得到u[i]
而如何处理d呢?把这棵树强行倒转,使儿子成为父亲,父亲成为儿子,那结论就一模一样了,但是子节点数量变化了
但是易得 d[i]=2*(n-siz[i])-1,最后就是边读入边处理,每次跳到v的位置继续
然后你会发现,小数是虚晃一枪23333
#include<bits/stdc++.h> using namespace std; #define N 100010 #define ll long long int t,n,m,q,cnt; int dep[N],f[N][20],first[N]; ll up[N],down[N],siz[N]; struct email { int u,v; int nxt; }e[N*4]; inline void add(int u,int v) { e[++cnt].nxt=first[u];first[u]=cnt; e[cnt].u=u;e[cnt].v=v; } void pre(int u,int fa) { for(int i=1;(1<<i)<=dep[u];i++) f[u][i]=f[f[u][i-1]][i-1]; for(int i=first[u];i;i=e[i].nxt) { int v=e[i].v; if(v==fa)continue; dep[v]=dep[u]+1; f[v][0]=u; pre(v,u); } } inline int lca(int x,int y) { if(dep[x]<dep[y]) swap(x,y); int t=dep[x]-dep[y]; for(int i=0;(1<<i)<=t;i++) if(t&(1<<i)) x=f[x][i]; if(x==y)return x; for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; return f[x][0]; } void dfs(int u,int fa) { siz[u]=1; for(int i=first[u];i;i=e[i].nxt) { int v=e[i].v; if(v==fa)continue; dfs(v,u); siz[u]+=siz[v]; } } void dfs2(int u,int fa) { if(fa!=-1) up[u]=up[fa]+2*siz[u]-1,down[u]=down[fa]+2*(n-siz[u])-1; for(int i=first[u];i;i=e[i].nxt) { int v=e[i].v; if(v==fa)continue; dfs2(v,u); } } inline void init() { cnt=0; memset(f,0,sizeof(f)); memset(up,0,sizeof(up)); memset(siz,0,sizeof(siz)); memset(down,0,sizeof(down)); memset(first,0,sizeof(first)); } int main() { scanf("%d",&t); while(t--) { init(); scanf("%d",&n); for(int i=1;i<n;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v);add(v,u); } pre(0,-1);dfs(0,-1);dfs2(0,-1); scanf("%d",&q); while(q--) { ll ans=0; int k,u; scanf("%d%d",&k,&u); for(int i=1;i<=k;i++) { int v;scanf("%d",&v); int LCA=lca(u,v); ans+=up[u]-up[LCA]+down[v]-down[LCA]; u=v; } printf("%lld.0000\n",ans); } if(t)printf("\n"); } }
标签:define 整数 i++ bit style tput col turn 说明
原文地址:https://www.cnblogs.com/NSD-email0820/p/9801062.html