zoukankan      html  css  js  c++  java
  • BZOJ 3727 DP?推式子..

     思路:

    设$sum[i]表示i的子树中a[i]的和$

    $b[1]=Sigma a[i]*dis[i] = Sigma _{i=2} ^n sum[i]$

    $b[x]-b[fa[x]]=sum[1]-2*sum[x]$

    $sum[1]={Sigma_{i=2}^n (b[x]-b[fa[x]])+2*b[1] over n-1}$

    $求出sum[1]以后根据a[x]=sum[x]-Sigma_{v是x的儿子} sum[v]带入求出其它值即可$

    $复杂度O(n)$

    //By SiriusRen
    #include <cstdio>
    #include <cstring>
    using namespace std;
    #define int long long
    const int N=600500;
    int n,xx,yy,first[N],next[N],v[N],tot,fa[N],rev[N],cnt,b[N],X;
    long long sum[N],ans[N];
    void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;}
    void dfs(int x){
        rev[++cnt]=x;
        for(int i=first[x];~i;i=next[i])if(v[i]!=fa[x])
            fa[v[i]]=x,dfs(v[i]);
    }
    void dfs2(int x){
        ans[x]=sum[x];
        for(int i=first[x];~i;i=next[i])if(v[i]!=fa[x])
            dfs2(v[i]),ans[x]-=sum[v[i]];
    }
    signed main(){
        memset(first,-1,sizeof(first));
        scanf("%lld",&n);
        for(int i=1;i<n;i++)scanf("%lld%lld",&xx,&yy),add(xx,yy),add(yy,xx);
        for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
        dfs(1);
        for(int i=2;i<=n;i++)sum[1]+=(b[i]-b[fa[i]]);
        sum[1]=(sum[1]+2*b[1])/(n-1);
        for(int i=2;i<=n;i++)X=rev[i],sum[X]=(sum[1]-b[X]+b[fa[X]])/2;
        dfs2(1);
        for(int i=1;i<=n;i++)printf("%lld%c",ans[i],i!=n?' ':'
    ');
    }
  • 相关阅读:
    广度优先搜索(一)
    快速幂
    office 2013
    最著名的十大公式
    二分查找的上下界
    双关键字快速排序
    字符串操作
    分治算法练习(二)
    P3119 [USACO15JAN]草鉴定[SCC缩点+SPFA]
    P3225 [HNOI2012]矿场搭建[割点]
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6667250.html
Copyright © 2011-2022 走看看