hdu6133

来源:互联网 发布:java界面布局类型 编辑:程序博客网 时间:2024/06/11 23:45

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;}