• 【BZOJ 3727】 3727: PA2014 Final Zadanie (递推)


    3727: PA2014 Final Zadanie

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 279  Solved: 121

    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个整数b[i](0<=b[i]<=10^9)。

    Output

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

    Sample Input

    2
    1 2
    17 31

    Sample Output

    31 17

    HINT

    Source

    【分析】

      高斯消元肯定是不行的。

      直接计算肯定是不行的。

      output那个多解那句话一脸嘲讽肯定是唯一解的。

      好了,肯定是和父亲差分,这样的式子才靠谱。

      有:b[fa[i]]-b[i]=sum[i]-(tot-sum[i])=2*sum[i]-tot

      tot是全树的a的和,你把1当成根的话就是sum[1]。

      这时候,大家都想把tot求出来。

      tot=b[fa[i]]-b[i]-2*sum[i]

      肯定是要加起来的。

      $(n-1)*tot=sum_{i=1}^{n-1} b[fa[i]]-b[i] -2*sum[i]$

      但是有sum[i]不知道的怎么破。。。聪明的别人看出来他们的和就是b[1]啊。

      就可以求tot了,有tot就可以求sum了,就可以求a了。。。

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 #define Maxn 300010
     8 #define LL long long
     9 
    10 struct node
    11 {
    12     int x,y,next;
    13 }t[Maxn*2];
    14 int len,first[Maxn];
    15 int fa[Maxn];
    16 LL sum[Maxn],a[Maxn],b[Maxn];
    17 
    18 void ins(int x,int y)
    19 {
    20     t[++len].x=x;t[len].y=y;
    21     t[len].next=first[x];first[x]=len;
    22 }
    23 
    24 void dfs(int x,int f)
    25 {
    26     fa[x]=f;
    27     for(int i=first[x];i;i=t[i].next) if(t[i].y!=f)
    28     {
    29         dfs(t[i].y,x);
    30     }
    31 }
    32 
    33 int main()
    34 {
    35     int n;
    36     scanf("%d",&n);
    37     len=0;
    38     memset(first,0,sizeof(first));
    39     for(int i=1;i<n;i++)
    40     {
    41         int x,y;
    42         scanf("%d%d",&x,&y);
    43         ins(x,y);ins(y,x);
    44     }
    45     for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
    46     dfs(1,0);
    47     LL sm=0;
    48     for(int i=2;i<=n;i++) sm+=b[i]-b[fa[i]];
    49     sm+=2*b[1];
    50     sm/=(n-1);sum[1]=sm;
    51     for(int i=2;i<=n;i++) sum[i]=(b[fa[i]]-b[i]+sm)/2;
    52     for(int i=1;i<=n;i++) a[i]=sum[i];
    53     for(int i=2;i<=n;i++) a[fa[i]]-=sum[i];
    54     for(int i=1;i<n;i++) printf("%lld ",a[i]);printf("%d
    ",a[n]);
    55     return 0;
    56 }
    View Code

    LONG LONG

    2017-04-08 09:47:14

  • 相关阅读:
    python中装饰器的原理
    python中封装、继承、多态
    Linux 中数组的使用
    Linux中环境变量中文件执行顺序
    Linux中FTP的一点理解
    原来... 拷贝构造函数的参数为什么必须使用引用类型
    C++ Programming language读书笔记
    linux 用户态 内核态
    Linux命令学习整理。
    fork &vfork --陈皓
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6680945.html
Copyright © 2020-2023  润新知