hdu6133

Though being cruel and merciless in the battlefields, the total obedience to the command hierarchy makes message delivering between Stormtroopers quite inefficient, which finally caused the escape of Luke Skywalker, the destroy of the Death Star, and the collapse of the Galactic Empire.

In particular, the hierarchy of Stormtroopers is defined by a binary tree. Everyone in the tree has at most two direct subordinates and exactly one direct leader, except the first (numbered 11) Stormtrooper, who only obey the order of the Emperor.

It has been a time-consuming task for the Stormtroopers to input messages into his own log system. Suppose that the ii-th Stormtrooper has a message of length aiai, which means that it costs aiai time to input this message into a log system. Everyone in the hierarchy has the mission of collecting all messages from his subordinates (a direct or indirect children in the tree) and input thses messages and his own message into his own log system.

Everyone in the hierarchy wants to optimize the process of inputting. First of all, everyone collects the messages from all his subordinates. For a Stormtrooper, starting from time 00, choose a message and input it into the log system. This process proceeds until all messages from his subordinates and his own message have been input into the log system. If a message is input at time tt, it will induce tt units of penalty.

For every Stormtrooper in the tree, you should find the minimum penalty.
Input
The first line of the input contains an integer TT, denoting the number of test cases.

In each case, there are a number nn (1≤n≤1051≤n≤105) in the first line, denoting the size of the tree.

The next line contains nn integers, the ii-th integer denotes aiai (0≤ai≤1080≤ai≤108), the ii-th Stormtrooper’s message length.

The following n−1n−1 lines describe the edges of the tree. Each line contains two integers u,vu,v (1≤u,v≤n1≤u,v≤n), denoting there is an edge connecting uu and vv.
Output
For each test case, output nn space-separated integers in a line representing the answer. ii-th number is the minimum penalty of gathering messages for ii-th Stormtrooper.
Sample Input
1
3
1 2 3
1 2
2 3
Sample Output
10 7 3
題意:
類似於排隊計算每個人所需要的等候時間問題,只不過是現在出現在了二叉樹中。

#include <queue>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <vector>
#include <map>
#include <assert.h>
#include <algorithm>
using namespace std;
#define debug printf("%s %d\n", __FUNCTION__, __LINE__)

const int maxn = 1e5 + 10;

int n, unique_n;
int w[maxn], value_list[maxn], id[maxn], size[maxn];
int left_son[maxn], right_son[maxn];
long long cnt_num[maxn], cnt_sum[maxn];
vector<int> e[maxn];

//計算每一棵子樹的大小,將小的那棵放左邊,大的放右邊
int get_size(int u, int pre) {
    size[u] = 1;
    for (int i = 0; i < e[u].size(); i++) 
        if (e[u][i] != pre) {
            if (left_son[u] == -1) left_son[u] = e[u][i];
            else right_son[u] = e[u][i];
            size[u] += get_size(e[u][i], u);
        }
    if (~left_son[u] && ~right_son[u] && size[ left_son[u] ] > size[ right_son[u] ])
        swap(left_son[u], right_son[u]);
    return size[u];
}

long long query(long long *r, int x) {
    long long rt = 0;
    while (x) {
        rt += r[x];
        x -= x & -x;
    }
    return rt;
}

void update(long long *r, int x, int value) {
    if (x == 0) return ;
    while (x <= unique_n) {
        r[x] += value;
        x += x & -x;
    }
}

long long current_answer;
long long f[maxn];

void add_number(int inx) {
//更新答案的過程類似於在一個正在排隊的隊伍中,插入另外一個人,會導致整個等待時間總和變化的計算方法
    current_answer += (query(cnt_num, unique_n) - query(cnt_num, inx)) * value_list[inx] + value_list[inx];
    current_answer += query(cnt_sum, inx);
    update(cnt_num, inx, 1);
    update(cnt_sum, inx, value_list[inx]);
    //cout << '+' << w[inx] << endl;
    //cout << current_answer << endl;
}

void del_number(int inx) {
    update(cnt_num, inx, -1);
    update(cnt_sum, inx, -value_list[inx]);
    current_answer -= (query(cnt_num, unique_n) - query(cnt_num, inx)) * value_list[inx] + value_list[inx];
    current_answer -= query(cnt_sum, inx);
}
//刪掉某棵子樹
void clean(int u) {
    del_number(id[u]);
    if (~left_son[u]) clean(left_son[u]);
    if (~right_son[u]) clean(right_son[u]);
}
//恢復某棵子樹
void validate(int u) {
    add_number(id[u]);
    if (~left_son[u]) validate(left_son[u]);
    if (~right_son[u]) validate(right_son[u]);
}

void get_ans(int u) {
    //如果這是葉子節點
    if (!~left_son[u]) {
        f[u] = w[u];
        add_number(id[u]);
        return ;
    }

    //不是葉子節點,優先計算左子樹,因爲左子樹的size小,這樣可以計算出更加小的結果。
    get_ans(left_son[u]);

    if (~right_son[u]) {
    //如果右子樹不爲空,那麼就要右子樹的值,由於左右子樹的計算相對獨立
    //因此在計算右子樹的時候,要先把左子樹清空,以防止影響計算。
    //同時由於後面還要計算根,計算完右子樹後,要把左子樹恢復
        clean(left_son[u]);
        get_ans(right_son[u]);
        validate(left_son[u]);
        add_number(id[u]);
        f[u] = current_answer;
    }
    else {
       //沒有右子樹,就直接計算根
        add_number(id[u]);
        f[u] = current_answer;
    }
}

int main(int argc, char **argv) {
    ios_base::sync_with_stdio(false);
    int cases;
    cin >> cases;

    while (cases--) {
        cin >> n;
        assert(100000);
        for (int i = 1; i <= n; i++) {
            cin >> w[i];
            value_list[i] = w[i];
            assert(w[i] <= 100000000 && 1 <= w[i]);
        }
        sort(value_list + 1, value_list + n + 1);
        unique_n = unique(value_list + 1, value_list + n + 1) - value_list - 1;

        current_answer = 0;
        for (int i = 1; i <= unique_n; i++) 
            cnt_num[i] = cnt_sum[i] = 0;

        for (int i = 1; i <= n; i++) {
            id[i] = lower_bound(value_list + 1, value_list + unique_n, w[i]) - value_list;
            left_son[i] = right_son[i] = -1;
        }

        for (int i = 1; i <= n; i++) e[i].clear();
        for (int i = 1, u, v; i < n; i++) {
            cin >> u >> v;
            e[u].push_back(v); e[v].push_back(u);
        }

        get_size(1, 0);
        get_ans(1);
        for (int i = 1; i <= n; i++) cout << f[i] << ' ';
        cout << endl;
    }
    return 0;
}
發佈了174 篇原創文章 · 獲贊 64 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章