BZOJ-3727: PA2014 Final Zadanie

[文章目录]

Description

“一棵n个点的树,每条边长度为1,第i个结点居住着a[i]个人。假设在i结点举行会议,所有人都从原住址沿着最短路径来到i结点,行走的总路程为b[i]。输出所有b[i]。”吉丽已经造好了数据,但熊孩子把输入文件中所有a[i]给删掉了。你能帮他恢复吗?2<=n<=300000 0<=b[i]<=10^9

正推式子的方程:设siz[x]表示x子树的a[i]的和。y为x的儿子,整个树的根为rot
b[y]=b[x]+siz[rot]-2*siz[y]
发现方程只有n-1个,而未知的siz有n个。。。
考虑根:b[rot]=作为第n个方程。

之后就随便了。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 301000 
using namespace std;
typedef long long ll;
int n;
int b[N],head[N],to[N<<1],nxt[N<<1],fa[N],cnt;
ll sum,s[N];
inline void add(int x,int y)
{
    to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt;
}
void dfs(int x)
{
    for(int i=head[x];i;i=nxt[i]) if(to[i]!=fa[x])
    {
        fa[to[i]]=x;
        dfs(to[i]);
    }
}
void dfs1(int x)
{
    for(int i=head[x];i;i=nxt[i]) if(to[i]!=fa[x])
    {
        s[to[i]]=(sum+b[x]-b[to[i]])>>1;
        dfs1(to[i]);
    }
}
int main()
{
    scanf("%d",&n); int x,y;
    for(int i=1;i!=n;++i)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    for(int i=1;i<=n;++i) scanf("%d",b+i);
    dfs(1); sum=b[1]<<1;
    for(int i=2;i<=n;++i) sum+=b[i]-b[fa[i]];
    sum/=(n-1); s[1]=sum;
    dfs1(1); ll a;
    for(int i=1;i<=n;++i)
    {
        a=s[i];
        for(int j=head[i];j;j=nxt[j]) if(to[j]!=fa[i]) a-=s[to[j]];
        printf("%lld%c",a,(i==n)?'\n':' ');
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注