JZOJ 5444. 【NOIP2017提高A组冲刺11.2】救赎

来源:互联网 发布:淘宝otc货到付款可信吗 编辑:程序博客网 时间:2024/06/05 11:38

Description

“是的。”我回答,“我不会忘记你。在森林里我会一点点记起往日的世界。要记起的大概很多很多:各种人、各种场所、各种光、各种歌曲……”
——村上春树《世界尽头与冷酷仙境》

在没有心存在的世界尽头,音乐能够使小镇居民消散的心重新聚拢成形。作为镇子里唯一一个还残留着些许音乐记忆的人,我逐渐记起了往昔点滴……

记忆中有一棵无根树,有n个节点。
对于一棵有根树的每一个非叶子节点,我们都等概率选中其一个儿子节点作为偏好儿子。对于一条从父亲指向儿子的树边(u,v),如果v是u的偏好儿子,则称这条边为重边,否则为轻边。
我们定义一棵有根树的权值为其每一个节点到根路径上的轻边条数的和的期望值。
请对无根树每一个节点输出其为根的有根树的权值。答案模998244353。

Input

文件第一行是一个正整数n。
接下来n-1行,每行两个正整数(x,y)表示一条树边。

Output

输出文件共n行,每一行一个整数表示答案。

Sample Input

5
1 2
1 3
3 4
3 5

Sample Output

3
1
665496238
499122178
499122178

Data Constraint

对于10%的数据,保证n<=10。
对于30%的数据,保证n<=2000。
对于100%的数据,保证n<=10^5。

Solution

  • 利用期望的线性既可以得出对于一个有根树的答案是,复杂度 O(N2)

    i=1n(sizei1)(soni1)soni

  • 但是可以发现换一次根许多点的贡献都不变,

  • 那么我们先跑出以 1 为根的答案,每次 O(1) 换根后,更改相邻的边的贡献即可。

  • 而且我们可以 O(N) 预处理出 1N 的逆元,详细方法和证明见下面链接:

  • O(N) 求 1~N 逆元方法及证明

  • 这样时间复杂度就成了大常数的 O(N)

Code

#include<cstdio>using namespace std;typedef long long LL;const int N=1e5+1,mo=998244353;int n,tot;int first[N],next[N<<1],en[N<<1];int fa[N],size[N],son[N];LL ans[N],inv[N];inline int read(){    int X=0,w=1; char ch=0;    while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}    while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();    return X*w;}inline void write(int x){    if(x>9) write(x/10);    putchar(x%10+'0');}inline void insert(int x,int y){    next[++tot]=first[x];    first[x]=tot;    en[tot]=y;}inline void dfs(int x){    size[x]=1,son[x]=0;    for(int i=first[x];i;i=next[i])        if(en[i]!=fa[x])        {            fa[en[i]]=x;            son[x]++;            dfs(en[i]);            size[x]+=size[en[i]];        }}inline void find(int x){    if(fa[x]) ans[1]=(ans[1]+(son[fa[x]]-1)*inv[son[fa[x]]]%mo*size[x])%mo;    for(int i=first[x];i;i=next[i])        if(en[i]!=fa[x]) find(en[i]);}inline void work(int x){    int y=fa[x];LL sum=0;    if(son[y]) sum=(sum+mo-(n-1)*(son[y]-1)*inv[son[y]]%mo)%mo;    if(son[x]) sum=(sum+mo-(size[x]-1)*(son[x]-1)%mo*inv[son[x]]%mo)%mo;    fa[y]=x,fa[x]=0;    son[x]++,son[y]--;    int z=size[x];size[x]=n,size[y]-=z;    if(son[x]) sum=(sum+(n-1)*(son[x]-1)%mo*inv[son[x]]%mo)%mo;    if(son[y]) sum=(sum+(size[y]-1)*(son[y]-1)%mo*inv[son[y]]%mo)%mo;    ans[x]=(ans[y]+sum)%mo;    for(int i=first[x];i;i=next[i])        if(en[i]!=y) work(en[i]);    fa[x]=y,fa[y]=0;    son[x]--,son[y]++;    size[x]=z,size[y]=n;}int main(){    n=read();    for(int i=1;i<n;i++)    {        int x=read(),y=read();        insert(x,y);        insert(y,x);    }    inv[0]=inv[1]=1;    for(int i=2;i<=n;i++) inv[i]=(mo-mo/i)*inv[mo%i]%mo;    dfs(1),find(1);    for(int i=first[1];i;i=next[i]) work(en[i]);    for(int i=1;i<=n;i++) write(ans[i]),putchar('\n');    return 0;}
阅读全文
1 0
原创粉丝点击