Description

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

Input

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

Output

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

Sample Input

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

Sample Output

9
5 

Data Constraint

对于 20%的数据, N <= 10.
对于 40%的数据, N <= 1000.
另有 20%的数据, 保证给定的树是一条链.
对于 100%的数据, N <= 100000, Q <= 100000. 

Hint

题解

  • 首先,设d[i]为i的出度,f[i]为从i走向根节点的期望步数,g[i]为从根节点走到i的期望步数
  • 那么,f[i]=1/d[i]+Σ(f[i]+f[son]+1)/d[i]
  • 其实就是
  • ①直接走到父亲的期望1/d[i]
  • ②走到儿子,然后走回i,再到父亲的期望
  • 那么,g[i]=1/d[fa[i]]+(1+g[i]+g[fa[i]])/d[fa[i]]+Σ(son!=i)(1+g[i]+f[son])/d[fa[i]]
  • 其实就是
  • ①直接走到i的期望1/d[i]
  • ②走到爷爷,然后走回父亲,再走到i的期望
  • ③走到非i的儿子,然后走回父亲,再走到i的期望
  • 然后将f[i]化简一下:
  • f[i]=1/d[i]+Σ(f[i]+f[son]+1)/d[i]
  • d[i]*f[i]=1+Σ(f[i]+f[son]+1)
  • d[i]*f[i]=1+(d[i]-1)*f[i]+Σf[son]+d[i]-1
  • (d[i]-d[i]+1)*f[i]=d[i]+Σf[son]
  • f[i]=d[i]+Σf[son]
  • 再化简一下g[i]:
  • g[i]=1/d[fa[i]]+(1+g[i]+g[fa[i]])/d[fa[i]]+Σ(son!=i)(1+g[i]+f[son])/d[fa[i]]
  • d[fa[i]]*g[i]=1+1+g[i]+g[fa[i]]+Σ(son!=i)(1+g[i]+f[son])
  • d[fa[i]]*g[i]=2+g[i]+g[fa[i]]+(d[i]-2)+(d[i]-2)*g[i]+Σf[son]
  • d[fa[i]]*g[i]=d[i]+(d[i]-1)*g[i]+g[fa[i]]+Σf[son]
  • g[i]=d[i]+g[fa[i]]+Σf[son]
  • 然后就用dfs预处理出这两个数组
  • f[i]=f[i]+f[fa],g[i]=g[i]+g[fa],求到最大的祖先的期望步数
  • 对于一组询问u,v,路径就是u到lca,和v到lca
  • 那么ans=f[u]-f[lca]+g[v]-g[lca]

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cmath>
 5 using namespace std;
 6 const long long mo=1e9+7;
 7 struct edge {int to,from;}e[1000010*2];
 8 int n,q,head[1000010],cnt;
 9 long long sum,f[1000010][20],deep[1000010],ans,k1[1000010],k2[1000010];
10 void insert(int x,int y) {e[++cnt].to=y; e[cnt].from=head[x]; head[x]=cnt;}
11 void dfs(int x,int fa)
12 {
13     f[x][0]=fa;
14     k1[x]=0;
15     for (int i=head[x];i;i=e[i].from)
16         if (e[i].to!=fa)
17         {
18             dfs(e[i].to,x);
19             k1[x]=(k1[x]+k1[e[i].to]+1)%mo;
20         }
21     k1[x]=(k1[x]+1)%mo;
22 }
23 void dfs1(int x,int fa)
24 {
25     long long sum=0;
26     for (int i=head[x];i;i=e[i].from)
27         if (e[i].to!=fa) sum=(sum+k1[e[i].to]+1)%mo;
28         else sum=(sum+k2[x]+1)%mo;
29     for (int i=head[x];i;i=e[i].from)
30         if (e[i].to!=fa)
31         {
32             k2[e[i].to]=((sum-k1[e[i].to])%mo+mo)%mo;
33             dfs1(e[i].to,x);
34         }
35 }
36 void dfs2(int x,int fa)
37 {
38     deep[x]=deep[fa]+1;
39     k1[x]=(k1[x]+k1[fa])%mo,k2[x]=(k2[x]+k2[fa])%mo;
40     for (int i=head[x];i;i=e[i].from)
41         if (e[i].to!=fa)
42             dfs2(e[i].to,x);
43 }
44 int getlca(int u,int w)
45 {
46     if (deep[u]<deep[w]) swap(u,w);
47     int d=deep[u]-deep[w];
48     if (d) for (int i=0;i<=log(n)/log(2)+1&&d;i++,d>>=1) if (d&1) u=f[u][i];
49     if (u==w) return u;
50     for (int i=log(n)/log(2)+1;i>=0;i--)
51         if (f[u][i]!=f[w][i])
52             u=f[u][i],w=f[w][i];
53     return f[u][0];
54 }
55 int main()
56 {
57     freopen("tree.in","r",stdin);
58     freopen("tree.out","w",stdout);
59     scanf("%d%d",&n,&q);
60     for (int i=1;i<=n-1;i++)
61     {
62         int u,v;
63         scanf("%d%d",&u,&v);
64         insert(u,v),insert(v,u);
65     }
66     dfs(1,-1);
67     k1[1]=k2[1]=0;
68     dfs1(1,-1);
69     dfs2(1,-1);
70     for (int i=1;i<=log(n)/log(2)+1;i++)
71         for (int j=1;j<=n;j++)
72             f[j][i]=f[f[j][i-1]][i-1];
73     for (int i=1;i<=q;i++)
74     {
75         int u,v;
76         scanf("%d%d",&u,&v);
77         int lca=getlca(u,v);
78         printf("%lld\n",(k1[u]-k1[lca]+k2[v]-k2[lca]+mo)%mo);
79     }
80     return 0;
81 }

转载于:https://www.cnblogs.com/Comfortable/p/9475585.html

[树形dp] Jzoj P5814 树相关推荐

  1. [树形dp] Jzoj P5233 概率博弈

    Description 小A和小B在玩游戏.这个游戏是这样的: 有一棵n个点的以1为根的有根树,叶子有权值.假设有m个叶子,那么树上每个叶子的权值序列就是一个1->m 的排列. 一开始在1号点有 ...

  2. [树形dp] Jzoj P1046 寻宝之旅

    Description 探险队长凯因意外的弄到了一份黑暗森林的藏宝图,于是,探险队一行人便踏上了寻宝之旅,去寻找传说中的宝藏. 藏宝点分布在黑暗森林的各处,每个点有一个值,表示藏宝的价值.它们之间由一 ...

  3. [树形dp] Jzoj P3914 人品问题

    Description 网上出现了一种高科技产品--人品测试器.只要你把你的真实姓名输入进去,系统将自动输出你的人品指数.yzx不相信自己的人品为0.经过了许多研究后,yzx得出了一个更为科学的人品计 ...

  4. #树形dp#jzoj 1010 洛谷 3155 叶子的颜色

    题目 对于每个叶结点u,定义c[u]为从u到根结点的简单路径上第一个有色结点的颜色.给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少. 分析 这道题可以用树形dp,f[x][0/1]f[x ...

  5. 【NOIP模拟】彩色树【树形dp】【树链剖分性质】【复杂度分析】

    题意:一棵初始时为空的树,依次加入 nnn 个叶结点,每次加入后询问 用若干不同颜色的路径将树边染色后 每个点到根经过的颜色数 的最大值 的最小值. n≤106n\leq 10^6n≤106 首先发现 ...

  6. [概率][lca][dfs][树形dp] Jzoj P4225 宝藏

    Description Input Output Sample Input 231 01 221 0 12 0 2 140 12 03 013 0 1 0 1 Sample Output 1.0000 ...

  7. [树形dp] Jzoj P5906 传送门

    Description 8102年,Normalgod在GLaDOS的帮助下,研制出了传送枪.但GLaDOS想把传送枪据为己有,于是把Normalgod扔进了一间实验室.这间实验室是一棵有n个节点的树 ...

  8. AcWing323. 战略游戏(树形DP)题解

    题目传送门 题目描述 鲍勃喜欢玩电脑游戏,特别是战略游戏,但有时他找不到解决问题的方法,这让他很伤心. 现在他有以下问题. 他必须保护一座中世纪城市,这条城市的道路构成了一棵树. 每个节点上的士兵可以 ...

  9. AcWing285. 没有上司的舞会(树形DP)题解

    题目传送门 题目描述 Ural大学有N名职员,编号为1~N. 他们的关系就像一棵以校长为根的树,父节点就是子节点的直接上司. 每个职员有一个快乐指数,用整数 HiHi 给出,其中 1≤i≤N. 现在要 ...

最新文章

  1. android Camera照相机技术(二)定制拍照
  2. ScrollView的使用
  3. mybatis关联配置(一对多配置)
  4. python怎么删除列表创建_Python基础--列表创建访问删除
  5. 自增或自减例子:i++和++i的相同点和不同点
  6. 动态查找表之二叉搜索树
  7. jQuery删除节点和追加节点
  8. 20181016-10 每周例行报告
  9. 【java】java中文件监控WatchService使用
  10. 2018 年程序员求生欲测试题(全国卷)
  11. linux shell 数字计算详解
  12. 局域网不同网段远程桌面_自动化已非原来的自动化:看虚拟局域网技术应用到罗克韦尔的DCS...
  13. 【工控老马】PLC六路抢答器系统设计详解
  14. JavaScript --------WebS APIs学习之DOM(三)
  15. 【开发环境搭建】7. Vscode使用SFTP远程文件同步
  16. Image 图像转化为 PDF 文件
  17. 计算机什么是符号健,在电脑健盘上怎么打:符号
  18. 语音识别-基础(一):简介【语音转文本】
  19. OCR识别技术保险保单识别系统|车险保单识别寿险保单识别|助力保险理赔
  20. 微信小程序毕业设计题目音乐播放器+后台管理系统|前后分离VUE.js

热门文章

  1. Jdk8的Stream流真香,来自程序员的花式表白
  2. H3C路由器常用命令
  3. 我的世界如何快速制作 服务器,《我的世界》颜色代码快速指南
  4. matlab函数_连通区域regionprops的相关解释
  5. 兆鹏带你读Watir——【第一节】创建IE对象篇
  6. IE浏览器系统兼容性问题
  7. 如何开发一个人人爱的组件?
  8. yii2解决中文乱码问题
  9. linux查看memcached安装路径,linux 怎么样 查看memcached是否安装成功
  10. 百度地图api 密钥获取