标签:str 规模 避免 display close 限制 lca 做了 bit
1775:梦中漫步
时间限制: 1000 ms 内存限制: 262144 KB
【题目描述】
梦游中的你来到了一棵N个结点的树上。
你一共做了Q个梦,每个梦需要你从点u走到点v之后才能苏醒。
由于你正在梦游,所以每到一个结点后,你会在它连出去的边中等概率地选择一条边走过去。
为了确保第二天能够准时到校,你要求出每个梦期望经过多少条边才能苏醒。为了避免精度误差,你要输出答案模1e9+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≤10。
对于40%的数据,N≤1000。
另有20%的数据,保证给定的树是一条链。
对于100%的数据,N≤100000,Q≤100000。
【题解】
类似于囧哥t4的套路。
定义dp[i]为从i节点走到它的父亲节点期望步数,siz[i]为i节点的亲儿子个数+1。
dp[i]=\frac{1}{siz[i]}*1+\sum (1+dp[v]+dp[i])*\frac{1}{siz[i]}。v是i的所有儿子。
移项化简得dp[i]=\sum dp[v]*\+siz[i]。
同理定义sh[i]表示i的祖先走到i的期望步数,求法类似。
最后倍增处理一哈,询问即可nlogn。
代码如下:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
const int mo=1e9+7;
int n,q,last[N],size,siz[N],dp[N],sh[N],f[N][20],g[N][20],h[N][20],dep[N];
struct pigu
{
int dao,ne;
}a[N<<1];
inline void lingjiebiao(int x,int y)
{
a[++size].dao=y;
a[size].ne=last[x];
last[x]=size;
}
inline int read()
{
char c=getchar();
int x=0,f=1;
while(!isdigit(c)) {if(c==‘-‘) f=-1;c=getchar();}
while(isdigit(c)) {x=(x<<3)+(x<<1)+c-‘0‘;c=getchar();}
return x*f;
}
inline void dfs(int now,int fa)
{
int daan=0;f[now][0]=fa;dep[now]=dep[fa]+1;
for(int i=1;f[f[now][i-1]][i-1];i++) f[now][i]=f[f[now][i-1]][i-1];
for(int i=last[now];i;i=a[i].ne)
{
if(a[i].dao==fa) continue;
siz[now]++;siz[a[i].dao]++;
dfs(a[i].dao,now);
daan+=dp[a[i].dao];
}
if(siz[now]==1) dp[now]=1;
else dp[now]=siz[now]+daan;
}
inline void dfs2(int now,int fa)
{
int huo=0;
for(int i=last[now];i;i=a[i].ne)
{
if(a[i].dao==fa) continue;
huo+=dp[a[i].dao];
}
if(fa) huo+=sh[now];
for(int i=last[now];i;i=a[i].ne)
if(a[i].dao!=fa)
sh[a[i].dao]=siz[now]+huo-dp[a[i].dao];
for(int i=last[now];i;i=a[i].ne)
if(a[i].dao!=fa)
dfs2(a[i].dao,now);
}
inline void dfs3(int now)
{
g[now][0]=dp[now];h[now][0]=sh[now];
for(int i=1;f[now][i];i++) g[now][i]=(g[now][i-1]+g[f[now][i-1]][i-1])%mo,h[now][i]=(h[now][i-1]+h[f[now][i-1]][i-1])%mo;
for(int i=last[now];i;i=a[i].ne)
{
if(f[now][0]==a[i].dao) continue;
dfs3(a[i].dao);
}
}
inline int get_lca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
for(int i=19;i>=0;i--)
if(dep[f[x][i]]>=dep[y]) 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];
}
int main()
{
n=read();q=read();
for(int i=1,x,y;i<=n-1;i++)
{
x=read();y=read();
lingjiebiao(x,y);
lingjiebiao(y,x);
}
dfs(1,0);
dfs2(1,0);
dfs3(1);
for(int i=1,x,y;i<=q;i++)
{
int ans=0;
x=read();y=read();
int lca=get_lca(x,y);
for(int i=19;i>=0;i--)
if(dep[f[x][i]]>=dep[lca])
ans+=g[x][i],ans%=mo,x=f[x][i];
for(int i=19;i>=0;i--)
if(dep[f[y][i]]>=dep[lca])
ans+=h[y][i],ans%=mo,y=f[y][i];
cout<<ans<<"\n";
}
return 0;
}
标签:str 规模 避免 display close 限制 lca 做了 bit
原文地址:https://www.cnblogs.com/betablewaloot/p/12247263.html