救赎
【问题描述】
“是的。”我回答,“我不会忘记你。在森林里我会一点点记起往日的世界。
要记起的大概很多很多:各种人、各种场所、各种光、各种歌曲„„”
——村上春树《世界尽头与冷酷仙境》
在没有心存在的世界尽头,音乐能够使小镇居民消散的心重新聚拢成形。作
为镇子里唯一一个还残留着些许音乐记忆的人,我逐渐记起了往昔点滴„„
记忆中有一棵无根树,有 n 个节点。
对于一棵有根树的每一个非叶子节点,我们都等概率选中其一个儿子节点作
为偏好儿子。对于一条从父亲指向儿子的树边(u,v),如果 v 是 u 的偏好儿子,
则称这条边为重边,否则为轻边。
我们定义一棵有根树的权值为其每一个节点到根路径上的轻边条数的和的
期望值。
请对无根树每一个节点输出其为根的有根树的权值。答案模 998244353。
【输入格式】
文件第一行是一个正整数 n。
接下来 n-1 行,每行两个正整数(x,y)表示一条树边。
【输出格式】
输出文件共 n 行,每一行一个整数表示答案。
【样例输入输出】
redemption.in
redemption.out
5
1
1 2
2
1 3
665496238
3 4
499122178
3 5
499122178
【数据范围】
对于 10%的数据,保证 n<=10。
对于 30%的数据,保证 n<=2000。
对于 100%的数据,保证 n<=10^5。
得到期望的式子
f[x]=∑f[v]*(1/son[x])+∑(f[v]+size[v])*(1-1/son[x])
先算出1为根的ans,那么其他点为根的ans可以推出
不断把根节点用dfs往下移,每一次移动只涉及2个点
递归回来后要换回来
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 #include<queue> 7 using namespace std; 8 typedef long long lol; 9 struct Node 10 { 11 int next,to; 12 }edge[200001]; 13 int head[100001],num,n; 14 lol size[100001],son[100001],Mod=998244353,f[100001],ans[100001]; 15 void add(int u,int v) 16 { 17 num++; 18 edge[num].next=head[u]; 19 head[u]=num; 20 edge[num].to=v; 21 } 22 lol qpow(lol x,lol y) 23 { 24 lol res=1; 25 while (y) 26 { 27 if (y&1) res=res*x%Mod; 28 x=x*x%Mod; 29 y=y/2; 30 } 31 return res; 32 } 33 void dfs(int x,int fa) 34 {int i; 35 size[x]=1; 36 for (i=head[x];i;i=edge[i].next) 37 { 38 int v=edge[i].to; 39 if (v!=fa) 40 { 41 dfs(v,x); 42 size[x]+=size[v]; 43 son[x]++; 44 } 45 } 46 lol rev=qpow(son[x],Mod-2); 47 for (i=head[x];i;i=edge[i].next) 48 { 49 int v=edge[i].to; 50 if (v!=fa) 51 { 52 f[x]+=(f[v]*rev%Mod)+(f[v]+size[v])*((son[x]-1)*rev)%Mod; 53 f[x]%=Mod; 54 } 55 } 56 } 57 void change_root(int x,int y) 58 {int i; 59 size[x]-=size[y];size[y]+=size[x]; 60 son[x]--;son[y]++; 61 f[x]=0;f[y]=0; 62 lol revx=qpow(son[x],Mod-2),revy=qpow(son[y],Mod-2); 63 for (i=head[x];i;i=edge[i].next) 64 { 65 int v=edge[i].to; 66 if (v!=y) 67 { 68 f[x]+=(f[v]*revx%Mod)+(f[v]+size[v])*((son[x]-1)*revx)%Mod; 69 f[x]%=Mod; 70 } 71 } 72 for (i=head[y];i;i=edge[i].next) 73 { 74 int v=edge[i].to; 75 f[y]+=(f[v]*revy%Mod)+(f[v]+size[v])*((son[y]-1)*revy)%Mod; 76 f[y]%=Mod; 77 } 78 ans[y]=f[y]; 79 } 80 void take_root(int x,int fa) 81 {int i; 82 for (i=head[x];i;i=edge[i].next) 83 { 84 int v=edge[i].to; 85 if (v!=fa) 86 { 87 change_root(x,v); 88 take_root(v,x); 89 change_root(v,x); 90 } 91 } 92 } 93 int main() 94 {int i,u,v; 95 cin>>n; 96 for (i=1;i<=n-1;i++) 97 { 98 scanf("%d%d",&u,&v); 99 add(u,v);add(v,u); 100 } 101 dfs(1,0); 102 printf("%lld\n",f[1]); 103 take_root(1,0); 104 for (i=2;i<=n;i++) 105 printf("%lld\n",ans[i]); 106 }