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.

题解

概率题,也就是套路嘛。
设fifif_i表示从i走的faifaifa_i的期望,
设gigig_i表示从faifaifa_i走的i的期望。

考虑fifif_i的转移,
首先它肯能直接走到它父亲,或者先走到某个儿子,再回到i,在走到它父亲。
fi=(1+∑x∈sonifx+fi+1)fi=(1+∑x∈sonifx+fi+1)f_i=(1+\sum _{x \in son_i}f_x+f_i+1)
整理一下:fi=∑x∈sonifxfi=∑x∈sonifxf_i=\sum _{x \in son_i}f_x
gigig_i的转移类似,直接从父亲走过来,或者父亲走到另外的儿子,然后再回到父亲,再走到i,
gi=gfai+degi+∑x∈soni,x≠ifxgi=gfai+degi+∑x∈soni,x≠ifxg_i=g_{fa_i}+deg_i+\sum_{x \in son_i,x≠i}f_x

直接bfs一次就可以求出f跟g了,
求一个前缀和,询问x到y的路径就是
x到lca,再从lca到y。

code

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string.h>
#include <cmath>
#include <math.h>
#define ll long long
#define N 100003
#define M 103
#define db double
#define P putchar
#define G getchar
using namespace std;
char ch;
void read(int &n)
{n=0;ch=G();while((ch<'0' || ch>'9') && ch!='-')ch=G();ll w=1;if(ch=='-')w=-1,ch=G();while('0'<=ch && ch<='9')n=(n<<3)+(n<<1)+ch-'0',ch=G();n*=w;
}int max(int a,int b){return a>b?a:b;}
int min(int a,int b){return a<b?a:b;}
void write(ll x){if(x>9) write(x/10);P(x%10+'0');}const int mo=1000000007;
int n,m,x,y,z,d[N],ans;
int tot,lst[N],to[N*2],nxt[N*2];
int q[N],head,tail,fa[17][N];
int f[N],g[N],dep[N],sum;void ins(int x,int y)
{nxt[++tot]=lst[x];to[tot]=y;lst[x]=tot;
}ll ksm(ll x,int y)
{ll s=1;for(;y;y>>=1,x=x*x%mo)if(y&1)s=s*x%mo;return s;
}void add(int& x,int y)
{x=x+y>mo?x+y-mo:x+y;
}void bfs()
{for(head=0,q[tail=1]=1;head<tail;){x=q[++head];for(int i=lst[x];i;i=nxt[i])if(to[i]!=fa[0][x]){fa[0][to[i]]=x;q[++tail]=to[i];}add(f[x],d[x]);}
}int lca(int x,int y)
{if(dep[x]<dep[y])swap(x,y);for(int j=16;j>=0;j--)if(dep[fa[j][x]]>=dep[y])x=fa[j][x];if(x==y)return x;for(int j=16;j>=0;j--)if(fa[j][x]!=fa[j][y])x=fa[j][x],y=fa[j][y];return fa[0][x];
}int main()
{freopen("tree.in","r",stdin);freopen("tree.out","w",stdout);read(n);read(m);for(int i=1;i<n;i++)read(x),read(y),d[x]++,d[y]++,ins(x,y),ins(y,x);bfs();for(int i=n;i;i--)for(int j=lst[q[i]];j;j=nxt[j])if(to[j]!=fa[0][q[i]])add(f[q[i]],f[to[j]]);f[1]=g[1]=0;for(int i=1;i<=n;i++){dep[q[i]]=dep[fa[0][q[i]]]+1;sum=g[q[i]]+d[q[i]];for(int j=lst[q[i]];j;j=nxt[j])if(to[j]!=fa[0][q[i]])add(sum,f[to[j]]);for(int j=lst[q[i]];j;j=nxt[j])if(to[j]!=fa[0][q[i]])g[to[j]]=(sum-f[to[j]]+mo)%mo;}for(int i=1;i<=n;i++)add(f[q[i]],f[fa[0][q[i]]]),add(g[q[i]],g[fa[0][q[i]]]);for(int j=1;j<17;j++)for(int i=1;i<=n;i++)fa[j][i]=fa[j-1][fa[j-1][i]];for(int i=1;i<=m;i++){read(x),read(y);z=lca(x,y);ans=0;add(ans,(f[x]-f[z]+mo)%mo);add(ans,(g[y]-g[z]+mo)%mo);printf("%d\n",ans);}return 0;
}

JZOJ5814. 【NOIP提高A组模拟2018.8.14】 树相关推荐

  1. jzoj5814 [NOIP提高A组模拟2018.8.14] 树 树形dp

    Description 梦游中的你来到了一棵 N 个节点的树上. 你一共做了 Q 个梦, 每个梦需要你从点 u 走到 点 v 之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中 ...

  2. 5814. 【NOIP提高A组模拟2018.8.14】 树(期望 + 倍增)

    5814. [NOIP提高A组模拟2018.8.14] 树 Problem 给定一棵nnn个点的树,m" role="presentation">mmm次询问,每次 ...

  3. JZOJ 5814. 【NOIP提高A组模拟2018.8.14】 树

    梦游中的你来到了一棵 N 个节点的树上. 你一共做了 Q 个梦, 每个梦需要你从点 u 走到点 v 之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中等概率地选择一条走过去, ...

  4. jzoj5814 【NOIP提高A组模拟2018.8.14】 树 (树上期望,递归法列方程)

    题面 梦游中的你来到了一棵 N 个节点的树上. 你一共做了 Q 个梦, 每个梦需要你从点 u 走到 点 v 之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中等概率地 选择一条 ...

  5. 5814. 【NOIP提高A组模拟2018.8.14】 树

    题目描述 梦游中的你来到了一棵 N 个节点的树上. 你一共做了 Q 个梦, 每个梦需要你从点 u 走到 点 v 之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中等概率地 选择 ...

  6. jzoj 5814. 【NOIP提高A组模拟2018.8.14】 树(期望)

    Description 梦游中的你来到了一棵 N 个节点的树上. 你一共做了 Q 个梦, 每个梦需要你从点 u 走到 点 v 之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中 ...

  7. jzoj 5814. 【NOIP提高A组模拟2018.8.14】树 dp+lca

    Description 梦游中的你来到了一棵 N 个节点的树上. 你一共做了 Q 个梦, 每个梦需要你从点 u 走到 点 v 之后才能苏醒, 由于你正在梦游, 所以每到一个节点后,你会在它连出去的边中 ...

  8. JZOJ 5820. 【NOIP提高A组模拟2018.8.16】 非法输入

    Description 在算法竞赛中,题目一般保证了输入数据的合法性.然而在工程开发中,我们往往不期望程 序得到的输入都是合法的. D 君正忙着向校内 OJ 添加题目,在写了第 233 个 val.c ...

  9. 5817. 【NOIP提高A组模拟2018.8.15】 抄代码

    Description J 君是机房的红太阳,每次模拟她总是 AK 虐场.然而在 NOIP2117 中,居然出现了另一位 AK 的选手 C 君! 这引起了组委会的怀疑,组委会认为 C 君有抄袭 J 君 ...

最新文章

  1. 配置linux终端主题需要密码,Mac/Ubuntu下终端色彩主题设置
  2. 4.6 前向和反向传播-深度学习-Stanford吴恩达教授
  3. graphpad prism怎么添加图例_Graphpad官网刚刚升级了!听说,新功能吊打R语言...........
  4. react 组件遍历】_从 Context 源码实现谈 React 性能优化
  5. seajs-require使用示例
  6. Linux gcc 制作静态库01
  7. java lpad oracle_Oracal的Lpad函数
  8. 11、doCreateBean中的initializeBean
  9. 死磕Android_App 启动过程(含 Activity 启动过程)
  10. Mtlab 二次规划及其例子
  11. E45: ‘readonly‘ option is set (add ! to override)解决办法
  12. Linux 流量监控
  13. 读书笔记:《遇见未知的自己》
  14. stata domin
  15. 中企海外周报 | 传祺GM6将亮相北美车展,锦江都城发力布局全球
  16. 【Google面试题】有四个线程1、2、3、4同步写入数据…C++11实现
  17. 高通平台安卓手机开机
  18. 千万别小瞧九宫格 一道题就能让候选人原形毕露!
  19. Wifi wpa_supplicant 到驱动的联系
  20. base64转MultipartFile并压缩得到压缩后对的MultipartFile

热门文章

  1. Origin 画局部示意图
  2. 【5.20_专辑】来聊聊程序猿的那些花式表白
  3. GridView嵌套GridView
  4. blob和arrayBuffer
  5. HTML给网站加上悬浮音乐播放器-毅世纪资源
  6. 5G商用后的资费会贵吗?
  7. 网页音乐播放器开发实战
  8. 申宝公司-钢铁等概念领涨
  9. 小学英语教育地方小城市与北京的差距
  10. wifi密钥破解(WPA2/PSK)