题目描述

梦游中的你来到了一棵$N$个节点的树上。你一共做了$Q$个梦,每个梦需要你从点$u$走到点$v$之后才能苏醒,由于你正在梦游,所以每到一个节点后,你会在它连出去的边中等概率地选择一条走过去,为了确保第二天能够准时到校,你要求出每个梦期望经过多少条边才能苏醒。为了避免精度误差,你要输出答案模${10}^9+7$的结果。


输入格式

第一行两个整数分别代表$N$和$Q$。接下来$N-1$行,每行两个整数$u,v$代表树中的一条边。接下来$Q$行,每行两个整数代表询问的$u,v$。


输出格式

一共$Q$行,每行一个整数代表答案。


样例

样例输入:

4 2
1 2
2 3
3 4
1 4
3 4

样例输出:

9
5


数据范围与提示

对于$20\%$的数据,$N\leqslant 10$。
对于$40\%$的数据,$N\leqslant 1,000$。
另有$20\%$的数据,保证给定的树是一条链。
对于$100\%$的数据,$N\leqslant 100,000,Q\leqslant 100,000$。
如果你求出的答案为$\frac{P}{Q}$($P,Q$互质),那么你需要输出$P\times Q^{{10}^9+5}$。


题解

从$u$走到$v$一定是从$u$到$fa[u]$,在到$fa[fa[u]],...,$再从$u,v$的$lca$一步一步走到$v$。
那么如果能够算出从$u$到$fa[u]$的期望步数(设为$f[u]$)和从$fa[u]$到$u$的期望步数(设为$g[u]$)就能够做了。

那么我们可以列出如下状态转移方程:

  $f[u]=\dfrac{1}{deg[u]}+\sum \limits_{x\in child[u]}\dfrac{f[x]+f[u]+1}{deg[u]}$

  $g[u]=\dfrac{1}{deg[fa[u]]}+\dfrac{g[u]+g[fa[u]]+1}{deg[fa[u]]}+\sum \limits_{x\in child[fa[u]]xor\ x\neq u}\dfrac{g[u]+f[x]+1}{deg[fa[u]]}$

发现式子就是在枚举第一步怎么走来列方程。
化简发现$f[u]$和$g[u]$其实是整数。
先求$f$,再求$g$,然后求$lca$就可以了。

三遍$DFS$即可求出答案。

时间复杂度:$\Theta(3\times N)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec
{
int nxt;
int to;
}e[200000];
int head[100001],cnt;
int n,q;
int fa[100001][18],depth[100001];
long long f[100001],g[100001];
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void pre_dfs(int x)
{
for(int i=head[x];i;i=e[i].nxt)
if(!depth[e[i].to])
{
fa[e[i].to][0]=x;
for(int j=1;j<=17;j++)
fa[e[i].to][j]=fa[fa[e[i].to][j-1]][j-1];
depth[e[i].to]=depth[x]+1;
pre_dfs(e[i].to);
}
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa[x][0])
f[x]+=f[e[i].to]+1;
f[x]++;
}
void pro_dfs(int x)
{
long long res=0;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to==fa[x][0])res+=g[x]+1;
else res+=f[e[i].to]+1;
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa[x][0])
{
g[e[i].to]=res-f[e[i].to];
pro_dfs(e[i].to);
}
}
void wzc_dfs(int x)
{
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa[x][0])
{
f[e[i].to]+=f[x];
g[e[i].to]+=g[x];
wzc_dfs(e[i].to);
}
}
int LCA(int x,int y)
{
if(depth[x]>depth[y])swap(x,y);
for(int i=17;~i;i--)
if(depth[fa[y][i]]>=depth[x])y=fa[y][i];
if(x==y)return x;
for(int i=17;~i;i--)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<n;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
depth[1]=1;
pre_dfs(1);
f[1]=0;
pro_dfs(1);
wzc_dfs(1);
while(q--)
{
int x,y;
scanf("%d%d",&x,&y);
int lca=LCA(x,y);
printf("%lld\n",(f[x]-f[lca]+g[y]-g[lca])%1000000007);
}
return 0;
}

rp++

[CSP-S模拟测试]:树(树形DP+期望)的更多相关文章

  1. 4.13 省选模拟赛 树 树形dp 卷积 NTT优化dp.

    考试的时候 看到概率 看到期望我就怂 推了一波矩阵树推自闭了 发现 边权点权的什么也不是. 想到了树形dp 维护所有边的断开情况 然后发现数联通块的和再k次方过于困难. 这个时候 应该仔细观察一下 和 ...

  2. BZOJ2878 [Noi2012]迷失游乐园 【基环树 + 树形dp + 期望dp】

    题目链接 BZOJ2878 题解 除了实现起来比较长,思维难度还是挺小的 观察数据范围发现环长不超过\(20\),而我们去掉环上任何一个点就可以形成森林 于是乎我们枚举断掉的点,然后只需求出剩余每个点 ...

  3. 【BZOJ-2286】消耗战 虚树 + 树形DP

    2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2120  Solved: 752[Submit][Status] ...

  4. [CF697D]Puzzles 树形dp/期望dp

    Problem Puzzles 题目大意 给一棵树,dfs时随机等概率选择走子树,求期望时间戳. Solution 一个非常简单的树形dp?期望dp.推导出来转移式就非常简单了. 在经过分析以后,我们 ...

  5. 51nod 1353 树 | 树形DP经典题!

    51nod 1353 树 | 树形DP好题! 题面 切断一棵树的任意条边,这棵树会变成一棵森林. 现要求森林中每棵树的节点个数不小于k,求有多少种切法. 数据范围:\(n \le 2000\). 题解 ...

  6. 【BZOJ-3572】世界树 虚树 + 树形DP

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1084  Solved: 611[Submit][Status ...

  7. bzoj 2286(虚树+树形dp) 虚树模板

    树链求并又不会写,学了一发虚树,再也不虚啦~ 2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5002  Sol ...

  8. 洛谷 P1453 城市环路 ( 基环树树形dp )

    题目链接 题目背景 一座城市,往往会被人们划分为几个区域,例如住宅区.商业区.工业区等等.B市就被分为了以下的两个区域--城市中心和城市郊区.在着这两个区域的中间是一条围绕B市的环路,环路之内便是B市 ...

  9. BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP+树剖lca

    BZOJ_2286_[Sdoi2011]消耗战_虚树+树形DP Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的 ...

  10. P2495 [SDOI2011]消耗战 lca倍增+虚树+树形dp

    题目:给出n个点的树  q次询问  问切断 k个点(不和1号点联通)的最小代价是多少 思路:树形dp  sum[i]表示切断i的子树中需要切断的点的最小代价是多少 mi[i]表示1--i中的最小边权 ...

随机推荐

  1. Drone 持续集成实践 - 基于 Gogs,以 Golang 为例

    Drone 官方示例 - Example Go project 用 Docker 部署 Go 服务器 Golang 官方示例 - outyet 一个生产环境的例子 用 rsync 复制文件的方式进行部 ...

  2. Google File System 论文阅读笔记

    核心目标:Google File System是一个面向密集应用的,可伸缩的大规模分布式文件系统.GFS运行在廉价的设备上,提供给了灾难冗余的能力,为大量客户机提供了高性能的服务. 1.一系列前提 G ...

  3. 移动端web整理 移动端问题总结,移动web遇到的那些坑

    meta基础知识 H5页面窗口自动调整到设备宽度,并禁止用户缩放页面 忽略将页面中的数字识别为电话号码 忽略Android平台中对邮箱地址的识别 当网站添加到主屏幕快速启动方式,可隐藏地址栏,仅针对i ...

  4. 洛谷 P1731 [NOI1999]生日蛋糕(搜索剪枝)

    题目链接 https://www.luogu.org/problemnew/show/P1731 解题思路 既然看不出什么特殊的算法,显然是搜索... dfs(u,v,s,r0,h0)分别表示: u为 ...

  5. tornado ioloop current和instance的一些区别

    import tornado.ioloop # 此时_current没有instance print dir(tornado.ioloop.IOLoop._current) # 通过instance ...

  6. C#学习大纲

    一.C#:    1.进制转换    2.vs界面内容 熟悉软件    3.数据类型 :引用类型 值类型    4.变量 (存储数据)一个变量存储一个数据    5.类型转换    6.运算符:算数运 ...

  7. elasticsearch 基础 —— Get API

    Get API get API允许根据其id从索引中获取指定类型的JSON文档.以下示例从名为twitter的索引获取JSON文档,该索引类型名为_doc,id值为0: GET twitter/_do ...

  8. 使用macOS苹方替换Windows 10微软雅黑

    关于微软雅黑 Windows从Vista开始用到现在的”微软雅黑”十多年以来基本没什么大改动,而大家的显示器从CRT进化到了IPS高分屏,十年前看着还OK的字体现在在绝大多数屏幕上可能就是这个样子的: ...

  9. [算法学习]开始leetcode之旅

    在此记录一下用javascript刷leetcode的过程,每天都要坚持! 1.Two Sum Given an array of integers, find two numbers such th ...

  10. java23种设计模式(五)--组合模式

    转载:https://www.cnblogs.com/V1haoge/p/6489827.html定义:所谓组合模式,其实说的是对象包含对象的问题,通过组合的方式(在对象内部引用对象)来进行布局,我认 ...