bzoj3727 (这真的是树形DP?)

来源:互联网 发布:屏蔽一段ip的js代码 编辑:程序博客网 时间:2024/06/01 12:02

Description

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

Input

第一行一个整数n(2<=n<=300000)。
接下来n-1行,每行两个整数x,y,表示x和y之间有连边。
接下来一行由空格隔开的n个整数bi。

Output

输出一行由空格隔开的n个整数a[i]。
如果你觉得有多组解就任意输出其中一组。

Sample Input

2
1 2
17 31

Sample Output

31 17

我、不、是、很、相信、这是dp?

TJ:

我们让size[x]表示以x为根节点的子树的a的值的和,fa[x]表示x的父亲,那么:

b[1]=i=1na[i]deepib[x]=b[fa[x]]2size[x]+size[1]

变一变形
2size[x]size[1]=b[fa[i]]b[i]

右边可以求出来并且累加,所以我们换成
i=2nsize[i]size[1](n1)=i=2nb[fa[i]]b[i]

然后你发现其实ni=2size[i]其实就是b[1](yy一下即可)
所以
size[1]=2b[1]ni=2b[fa[i]]b[i]n1

根据“变一变形”那个公式我们可以求出所有的size[i],又显然有
a[i]=size[i]size[son[x]]

然后就可以求粗来了。
Code不放了撒。

#include<cstring>#include<cstdio>using namespace std;typedef long long LL;const int N=300000+50;struct E {int v,nt;} e[N<<1];int n,cnt,tot,h[N],fa[N],id[N];LL b[N],sz[N];template <class T> void read(T &x) {    x=0;int f=1;char ch=getchar();    for(;ch<'0'||ch>'9';) {if(ch=='-') f=-1;ch=getchar();}    for(;ch>='0'&&ch<='9';) x=x*10+ch-'0',ch=getchar();    x*=f;}template <class T> void write(T x) {    int num=0;char ch[20];    if(x<0) putchar('-'),x=-x;    do ch[++num]=x%10+'0',x/=10; while(x);    for(;num;) putchar(ch[num--]);}void add(int u,int v) {e[++cnt]=(E){v,h[u]};h[u]=cnt;}void dfs(int x) {    id[++tot]=x;    for(int v,i=h[x];i;i=e[i].nt)        if((v=e[i].v)!=fa[x]) fa[v]=x,dfs(v);}int main() {    int i,u,v;    for(read(n),i=1;i<n;i++) read(u),read(v),add(u,v),add(v,u);    for(i=1;i<=n;i++) read(b[i]);    for(dfs(1),i=2;i<=n;i++) sz[1]+=b[fa[i]]-b[i];    for(sz[1]=(b[1]*2-sz[1])/(n-1),i=2;i<=n;i++) sz[i]=b[fa[i]]-b[i]+sz[1]>>1;    for(i=2;i<=n;i++) sz[fa[id[i]]]-=sz[id[i]];    for(i=1;i<n;i++) write(sz[i]),putchar(' ');    write(sz[n]),putchar('\n');    return 0;}
原创粉丝点击