我是靠谱客的博主 甜甜老鼠,最近开发中收集的这篇文章主要介绍jzoj5814 【NOIP提高A组模拟2018.8.14】 树 (树上期望,递归法列方程)题面失智题实现,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
题面
梦游中的你来到了一棵 N 个节点的树上. 你一共做了 Q 个梦, 每个梦需要你从点 u 走到 点 v 之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中等概率地 选择一条走过去, 为了确保第二天能够准时到校, 你要求出每个梦期望经过多少条边才能苏 醒. 为了避免精度误差, 你要输出答案模10^9 + 7的结果.
对于 100%的数据, N <= 100000, Q <= 100000.
失智题
一点想法都没有.jpg
只想到了这一点:
由于期望的线性性,我们可以对于每一条边计算贡献。
如果是图,这的确没什么用。 但是注意这是一颗树,对于有向边
(u,fa[u])
(
u
,
f
a
[
u
]
)
,走过他需要的期望步数是可以计算的:
fx=1+∑1+fc+fxdeg
f
x
=
1
+
∑
1
+
f
c
+
f
x
d
e
g
,其中f_c是x的儿子,deg是x的度数(当前可以选择的边数)。
这个方程的意义是: 有 1/deg 1 / d e g 的概率直接走过,其余的概率都是走入儿子,再从儿子走回来,再重复上述过程。
其中运用了一种将未知数自己列入方程的思想,就像递归一样。
对于自上往下的边也差不多是同理的。
这样做了之后,询问就是直接树上路径求和了。
(推式子之后可以发现边权只有整数)
实现
#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const int N = 1e5+10, mo = 1e9 + 7;
ll f[N],g[N],pg[N],pf[N];
int n,Q,final[N],nex[2*N],to[2*N],tot;
int w[N][20],d[N],sc[N],dep[N];
void link(int x,int y) {
to[++tot]=y,nex[tot]=final[x],final[x]=tot;
}
void dfs(int x,int fa) {
w[x][0] = fa;
for (int i = 1; i <= 18; i++)
w[x][i] = w[w[x][i-1]][i-1];
dep[x] = dep[fa] + 1;
for (int i = final[x]; i; i=nex[i]) {
int y = to[i]; if (y == fa) continue;
dfs(y,x);
d[x]++;
f[x] += f[y];
sc[x] += f[y];
}
if (x != 1) {
d[x]++;
f[x] += d[x];
}
}
void dfs2(int x,int fa) {
g[x] += g[fa] + d[fa];
for (int i = final[x]; i; i=nex[i]) {
int y = to[i]; if (y == fa) continue;
g[y] = sc[x] - f[y];
dfs2(y,x);
}
}
void dfs3(int x,int fa) {
pg[x] += pg[fa] + g[x];
pf[x] += pf[fa] + f[x];
for (int i = final[x]; i; i=nex[i]) {
int y = to[i]; if (y == fa) continue;
dfs3(y,x);
}
}
int lca(int x,int y) {
if(dep[x] < dep[y]) swap(x,y);
for (int i = 18; ~i; i--)
if (dep[w[x][i]] >= dep[y]) x = w[x][i];
if (x==y) return x;
for (int i = 18; ~i; i--)
if (w[x][i] != w[y][i])
x = w[x][i], y = w[y][i];
return w[x][0];
}
int main() {
freopen("tree.in","r",stdin);
freopen("tree.out","w",stdout);
cin>>n>>Q;
for (int i = 1; i < n; i++) {
int u,v; scanf("%d %d",&u,&v);
link(u,v), link(v,u);
}
dfs(1,0); f[1] = 0;
dfs2(1,0);
dfs3(1,0);
for (int i = 1; i <= Q; i++) {
int u,v; scanf("%d %d",&u,&v);
int l = lca(u,v);
ll ans = pf[u] - pf[l] + pg[v] - pg[l];
printf("%lldn",ans % mo);
}
}
最后
以上就是甜甜老鼠为你收集整理的jzoj5814 【NOIP提高A组模拟2018.8.14】 树 (树上期望,递归法列方程)题面失智题实现的全部内容,希望文章能够帮你解决jzoj5814 【NOIP提高A组模拟2018.8.14】 树 (树上期望,递归法列方程)题面失智题实现所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复