BSOJ6387题解
2024-09-05 12:42:25
算是刷新了我对树上问题的认知
首先第一问随便做一个 \(O(nk)\) 的 DP 就可以草过去,考虑第二问。
我们将问题分为两个部分:走儿子边的答案和走父亲边的答案。最后拼接一下就好了。
设 \(fd[u][k]\) 是走儿子边且距离不超过 \(k\) 的节点数量,\(fu[u][k]\) 是走父亲边的答案;\(gd[u][k]\) 是走儿子边的拥挤程度,\(gu[u][k]\) 同理。
这几个转移起来相当简单,不再赘述。可以做到 \(O(nk\log n)\) 或 \(O(n(k+\log n))\)。
#include<cstdio>
typedef unsigned ui;
const ui M=1e5+5,K=15,mod=1e9+7;
ui n,k,cnt,h[M],f[M],ans[M],fd[M][K],fu[M][K],gd[M][K],gu[M][K];
struct Edge{
ui v,nx;
}e[M<<1];
inline void Add(const ui&u,const ui&v){
e[++cnt]=(Edge){v,h[u]};h[u]=cnt;
e[++cnt]=(Edge){u,h[v]};h[v]=cnt;
}
inline void swap(ui&a,ui&b){
ui c=a;a=b;b=c;
}
inline ui pow(ui a,ui b){
ui ans(1);for(;b;b>>=1,a=1ull*a*a%mod)if(b&1)ans=1ull*ans*a%mod;return ans;
}
inline void init(const ui&u){
for(ui v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u])f[v]=u,init(v);
}
inline void DFS1(const ui&u){
for(ui i=0;i<=k;++i)fd[u][i]=gd[u][i]=1;
for(ui v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u]){
DFS1(v);
for(ui i=1;i<=k;++i){
fd[u][i]+=fd[v][i-1];gd[u][i]=1ull*gd[u][i]*gd[v][i-1]%mod;
}
}
for(ui i=0;i<=k;++i)gd[u][i]=1ull*gd[u][i]*fd[u][i]%mod;
}
inline void DFS2(const ui&u){
static ui t[K],inv[K];inv[1]=1;
for(ui i=0;i<=k;++i)fu[u][i]=gu[u][i]=1;
if(u!=1){
++fu[u][1];
gu[u][1]=1ull*gu[f[u]][0]*gd[f[u]][0]%mod*fu[u][1]%mod;
for(ui i=2;i<=k;++i){
const ui&sz1=fu[f[u]][i-1],&sz2=fd[f[u]][i-1],&sz3=fd[u][i-2];
fu[u][i]=sz1+sz2-sz3;
gu[u][i]=1ull*gu[f[u]][i-1]*gd[f[u]][i-1]%mod*(fu[u][i]-1)%mod*fu[u][i]%mod;
t[i]=1ull*gd[u][i-2]*sz1%mod*sz2%mod;
inv[i]=1ull*inv[i-1]*t[i]%mod;
}
inv[k]=pow(inv[k],mod-2);
for(ui i=k;i>1;--i)swap(inv[i],inv[i-1]),inv[i]=1ull*inv[i]*inv[i-1]%mod,inv[i-1]=1ull*inv[i-1]*t[i]%mod;
for(ui i=2;i<=k;++i)gu[u][i]=1ull*gu[u][i]*inv[i]%mod;
}
for(ui v,E=h[u];E;E=e[E].nx)if((v=e[E].v)^f[u])DFS2(v);
}
signed main(){
scanf("%u%u",&n,&k);
for(ui i=1;i<n;++i){
ui u,v;scanf("%u%u",&u,&v);
Add(u,v);
}
init(1);DFS1(1);DFS2(1);
for(ui u=1;u<=n;++u){
const ui&sz1=fd[u][k],sz2=fu[u][k];
ans[u]=1ull*gd[u][k]*gu[u][k]%mod*pow(1ull*sz1*sz2%mod,mod-2)%mod*(sz1+sz2-1)%mod;
printf("%u ",sz1+sz2-1);
}
printf("\n");
for(ui u=1;u<=n;++u)printf("%u ",ans[u]);
}
最新文章
- 源代码管理工具之SVN
- composer的安装以及laravel框架的安装(一)
- Mysql:Forcing close of thread xxx user: &#39;root&#39; 的解决方法
- HDU 3911 线段树区间合并、异或取反操作
- scrollview做定时来回滚动时,总出现错位的情况。
- Centos5.5内核升级
- PHP发送AT指令
- fastDFS同步问题讨论
- 如何使用 iOS 7 的 AVSpeechSynthesizer 国家有声读物(4)
- 洛谷 [p2294] [HNOI2005] 狡猾的商人
- ROC曲线的计算
- 一个C#程序员学习微信小程序路由的笔记
- CentOS7.6搭建redis4.0.1 cluster集群
- bzoj4170 极光
- 3、MHC主要组织相容性复合体
- Hadoop生态圈-CentOs7.5单机部署ClickHouse
- 基于虹软 2.0 人脸识别猜年龄 java版 demo
- LeetCode--258--各位相加*
- SQL-17 获取当前(to_date=&#39;9999-01-01&#39;)薪水第二多的员工的emp_no以及其对应的薪水salary
- 【java编程】java中什么是bridge method(桥接方法)
热门文章
- rsync 远程同步部署——上下行同步
- Apache——配置与应用
- 一招教你IDEA中Java程序如何打包,以及打包后如何运行
- 程序员的情人节「GitHub 热点速览 v.22.07」
- OSI七层协议&;TCP协议(三次握手四次挥手)
- Solution -「APIO 2018」「洛谷 P4630」铁人两项
- Solution -「NOI 2008」「洛谷 P3980」志愿者招募
- C++特殊成员函数及其生成机制
- windev中的内存机制及其与C语言中的内存指针相似性(一)
- 【.net】AppDoamin| 应用程序域