選根

有一顆有nn個結點樹,結點被編號爲11~nn,記根結點深度爲11,如果第ii個結點的深度是dd,則它貢獻的價值是d×wid\times{w_i} ,這棵樹的價值是所有結點的價值和 求當根結點爲11~nn時,樹的價值分別爲多少

輸入描述
第一行輸入一個整數TT,代表有TT組測試數據 對於每一組測試數據,第一行有11個整數nn,第二行有nn個整數wiw_i,接下來n1n-1行每行有兩個整數x,yx,y表示xxyy之間有一條邊

輸出描述
對於每組測試數據,在一行中輸出nn個整數,第ii個整數代表以ii結點爲根結點時樹的價值

數據範圍
1T10001≤T≤1000
1n21051≤n≤2\cdot{10}^5
1wi1081≤w_i≤10^8
n2105\sum{n}≤2\cdot{10}^5

輸出時每行末尾的多餘空格,不影響答案正確性

樣例輸入
2
6
5 2 8 1 7 8
4 5
5 6
2 5
1 3
4 3
5
1 1 1 1 1
1 2
2 3
3 4
4 5
樣例輸出
102 100 81 76 73 88
15 12 11 12 15

二次掃描與換根法。
初始設11號節點。sumw[i]sumw[i]爲以節點ii爲根的子樹中ww的和;sumv[i]sumv[i]爲以節點ii爲根的子樹的價值;W=i=1nw[i]W=\sum_{i=1}^n w[i]
ans[x]ans[x]爲以節點xx爲根是整棵樹的價值,則對於節點xx的子節點yyans[y]=ans[x]sumw[y]+Wsumw[y]ans[y] = ans[x] - sumw[y] + W - sumw[y]
樹形dp即可。時間複雜度爲O(n)O(n)

#include<bits/stdc++.h>

#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define sc(a) scahf("%c",&a);
#define ss(a) scanf("%s",a)
#define pi(a) printf("%d\n",a)
#define pl(a) printf("%lld\n",a)
#define pc(a) putchar(a)
#define ms(a) memset(a,0,sizeof(a))
#define repi(i, a, b) for(register int i=a;i<=b;++i)
#define repd(i, a, b) for(register int i=a;i>=b;--i)
#define reps(s) for(register int i=head[s];i;i=Next[i])
#define ll long long
#define ull unsigned long long
#define vi vector<int>
#define pii pair<int,int>
#define mii unordered_map<int,int>
#define msi unordered_map<string,int>
#define lowbit(x) ((x)&(-(x)))
#define ce(i, r) i==r?'\n':' '
#define pb push_back
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define pr(x) cout<<#x<<": "<<x<<endl
using namespace std;

inline int qr() {
    int f = 0, fu = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-')fu = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        f = (f << 3) + (f << 1) + c - 48;
        c = getchar();
    }
    return f * fu;
}

const int N = 2e5 + 10;
int head[N], ver[N << 1], Next[N << 1], tot;
int n, T;
ll sumw[N], sumv[N], ans[N], W;

inline void add(int x, int y) {
    ver[++tot] = y;
    Next[tot] = head[x];
    head[x] = tot;
}

inline void init() {
    repi(i, 1, n)head[i] = sumv[i] = 0;
    tot = W = 0;
}

void dfs(int x, int f) {
    reps(x) {
        int y = ver[i];
        if (y == f)continue;
        dfs(y, x);
        sumw[x] += sumw[y];
        sumv[x] += sumv[y];
    }
    sumv[x] += sumw[x];
}

void dp(int x, int f) {
    reps(x) {
        int y = ver[i];
        if (y == f)continue;
        ans[y] = ans[x] - sumw[y] + W - sumw[y];
        dp(y, x);
    }
}

int main() {
    T = qr();
    while (T--) {
        n = qr();
        init();
        repi(i, 1, n)sumw[i] = qr(), W += sumw[i];
        repi(i, 1, n - 1) {
            int x = qr(), y = qr();
            add(x, y), add(y, x);
        }
        dfs(1, 0);
        ans[1] = sumv[1];
        dp(1, 0);
        repi(i, 1, n)printf("%lld%c", ans[i], ce(i, n));
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章