2017多校联合第八场/hdu 6133 Army Formations(线段树合并)

Army Formations

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 894    Accepted Submission(s): 221


Problem Description
> Stormtroopers were the assault/policing troops of the Galactic Empire. Dissenting citizens referred to them as bucketheads, a derogatory nickname inspired by the bucket-shaped helmets of stormtroopers. They wore white armor made from plastoid over a black body glove which, in addition to creating an imposing image, was outfitted with a wide array of survival equipment and temperature controls that allowed its wearer to survive in most environments, and were designed to disperse blaster bolt energy. As members of the Stormtrooper Corps, an independent branch that operated under the Imperial Army, stormtroopers represented the backbone of the Imperial Military—trained for total obedience to the command hierarchy, as well as absolute loyalty to Emperor Sheev Palpatine and the Imperial regime. Stormtroopers were trained at Imperial Academies, and used a variety of weapons.
>
> --- Wookieepedia

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  1 ) 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  i -th Stormtrooper has a message of length  ai , which means that it costs  ai  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  0 , 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  t , it will induce  t  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  T , denoting the number of test cases.

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

The next line contains  n  integers, the  i -th integer denotes  ai  ( 0ai108 ), the  i -th Stormtrooper’s message length.

The following  n1  lines describe the edges of the tree. Each line contains two integers  u,v  ( 1u,vn ), denoting there is an edge connecting  u  and  v .
 

Output
For each test case, output  n  space-separated integers in a line representing the answer.  i -th number is the minimum penalty of gathering messages for  i -th Stormtrooper.
 

Sample Input
  
  
1 3 1 2 3 1 2 2 3
 

Sample Output
  
  
10 7 3
 

Source
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:   6181  6180  6179  6178  6177 
 

Statistic |  Submit |  Discuss |  Note

题意:给一个二叉树,n个节点,每个点的提交时间给出,每个节点总的提交任务的罚时为:提交这个节点和其子树所有的任务,每个任务提交时间的总和为该点的罚时。求每个节点提交完所有任务的最小罚时。

题解:其实题目要求的就是一颗子树上把所有的权值从小到大排序,每个值对应第k大,把k和值乘在一起加和,就是这个子树对应的根的答案。说到底就是有多少个数大于一个值,这个值就要多加几次。需要注意的是,值相同的情况。

对于每一个节点,我们建一个权值线段树,表示以此点为根的的子树上的权值分部情况。

然后右子树上有多少值大于左子树上的值,以及左子树上有多少值大于右子树上的值就很好求了,线段树合并的时候,左子树对应的线段树的左儿子的值一定小于右子树的线段树的右儿子,反之亦然,维护一下num代表个数,sum代表加和就好了。

这样的话,在左右子树都已经求出结果的情况下,我们只需要求出跨越左右子树需要加的值是多少,而这个过程就是上面的操作。

然后还需要注意下,这时候都没有考虑根节点,插入根节点要统计下子树中有多少值大于自己,所以要最后插入。

最后,就是前面提到的,需要注意下值重复的情况,对于左右子树值相同的情况我们在权值线段树里没有办法通过左右区间得到,然而实际情况是需要我们对相等的值进行一个随机排名的,所以在插入的时候,需要加上跟自己值相同的个数,在合并的时候,当递归到叶子节点,需要让左子树的sum*右子树的num,反之也可以。

代码:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <string.h>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <list>
#include <bitset>
#include <stack>
#include <stdlib.h>
#define lowbit(x) (x&-x)
#define e exp(1.0)
#define eps 1e-8
//ios::sync_with_stdio(false);
//    auto start = clock();
//    cout << (clock() - start) / (double)CLOCKS_PER_SEC<<endl;
typedef long long ll;
typedef long long LL;
using namespace std;
typedef unsigned long long ull;
const int maxn=1e5+10;
int a[maxn],b[maxn];
vector<int>vec[maxn];
ll tree[maxn*18],ans[maxn*18];
int size[maxn*18],root[maxn],lchild[maxn*18],rchild[maxn*18];
int tot,top;
void insert(int L,int R,int x,int root)
{
    ans[root]=tree[root]=b[x];
    size[root]=1;
    lchild[root]=rchild[root]=0;
    if(L==R)return ;
    int mid=(L+R)>>1;
    if(x<=mid)insert(L,mid,x,lchild[root]=++tot);
    else insert(mid+1,R,x,rchild[root]=++tot);
}
int Merge(int root1,int root2)
{
    if(!root1) return root2;
    if(!root2) return root1;
    lchild[root1]=Merge(lchild[root1],lchild[root2]);
    rchild[root1]=Merge(rchild[root1],rchild[root2]);
    tree[root1]+=tree[root2];
    size[root1]+=size[root2];
    if(!lchild[root1]&&!rchild[root1])ans[root1]=(tree[root1]/size[root1]+tree[root1])*size[root1]/2;
    else ans[root1]=ans[lchild[root1]]+ans[rchild[root1]]+tree[lchild[root1]]*size[rchild[root1]];
    return root1;
}
void dfs(int u,int fa)
{
    int pos=lower_bound(b+1,b+top,a[u])-b;
    insert(1,top-1,pos,root[u]=++tot);
    for(int i=0;i<vec[u].size();i++)
    {
        int to=vec[u][i];
        if(to==fa)continue;
        dfs(to,u);
        Merge(root[u],root[to]);
    }
}
int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin>>T;
    while(T--)
    {
        tot=0;
        for(int i=0;i<100005;i++)vec[i].clear(),ans[i]=tree[i]=size[i]=0;
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i],b[i]=a[i];
        sort(b+1,b+n+1);
        top=unique(b+1,b+n+1)-b;
        int u,v;
        for(int i=0;i<n-1;i++)
            cin>>u>>v,vec[u].push_back(v),vec[v].push_back(u);
        dfs(1,1);
        for(int i=1;i<=n;i++)cout<<ans[root[i]]<<' ';
        cout<<endl;
    }
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值