Hdu-6133 Army Formations(线段树合并)

185 篇文章 0 订阅
18 篇文章 0 订阅
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 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 i-th Stormtrooper has a message of length  ai ai, which means that it costs  ai 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 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 t, it will induce  t tunits 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 T, denoting the number of test cases. 

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

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

The following  n1 n−1 lines describe the edges of the tree. Each line contains two integers  u,v u,v ( 1u,vn 1≤u,v≤n), denoting there is an edge connecting  u u and  v v.
Output
For each test case, output  n n space-separated integers in a line representing the answer.  i i-th number is the minimum penalty of gathering messages for  i i-th Stormtrooper. 
Sample Input
1
3
1 2 3
1 2
2 3
Sample Output
10 7 3
分析:题意很迷,不过大概就是每棵子树的根都需要上传这棵子树上的所有信息,对于每棵子树我们只要把它要上传的信息排个序上传就可以了,现在显然不能暴力搞,考虑线段树合并,线段树维护三个信息,区间答案,区间和,还有区间有几个数,区间和和区间个数可以直接相加,区间答案就是ans[ls] + ans[rs] + sum[ls]*size[rs],一开始每个根的线段树中只插入它自己的值,然后递归合并,这样一开始树上有n*logn点,这样因为线段树合并是很自然的启发式合并,总复杂度应该是n*logn*log(n*logn),空间的话只要每次合并不开新点就能卡过,但这题卡内存,所以要注意线段树的写法不然会mle.
 
 
#include<stdio.h>  
#include<vector>  
#include<algorithm>  
#define N 100002
using namespace std;
typedef long long ll;
int T,n,m,u,v,cnt,rt[N],a[N],b[N];
ll Ans[N];
vector<int> G[N];
struct Node
{
	int ls,rs,size;
    ll ans,sum;
}tr[N*18];
int merge(int u,int v)
{
	if(!u || !v) return u + v;
	if(tr[u].ls || tr[u].rs) 
	{
		tr[u].ls = merge(tr[u].ls,tr[v].ls);
		tr[u].rs = merge(tr[u].rs,tr[v].rs);
		tr[u].sum = tr[tr[u].ls].sum +  tr[tr[u].rs].sum;
		tr[u].size = tr[tr[u].ls].size +  tr[tr[u].rs].size;
		tr[u].ans = tr[tr[u].ls].ans +  tr[tr[u].rs].ans + tr[tr[u].ls].sum * tr[tr[u].rs].size;
	}
	else
	{
		tr[u].ans = tr[u].ans + tr[v].ans + tr[u].sum*tr[v].size;
		tr[u].sum = tr[u].sum + tr[v].sum;
		tr[u].size = tr[u].size + tr[v].size;
	}
	return u;
}
void dfs(int u,int fa)
{
	for(int v : G[u])
	 if(v != fa) 
	 {
		 dfs(v,u);
		 merge(rt[u],rt[v]);
	 }
	Ans[u] = tr[rt[u]].ans;
}
void build(int &node,int l,int r,int pos)
{
	node = ++cnt;
	tr[node].sum = tr[node].ans = b[pos];
	tr[node].size = 1; 
	tr[node].ls = tr[node].rs = 0;
	if(l == r) return;
	int mid = (l+r)>>1;
	if(pos <= mid) build(tr[node].ls,l,mid,pos);
	else build(tr[node].rs,mid+1,r,pos);
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		cnt = 0;
		scanf("%d",&n);
		for(int i = 1;i <= n;i++) scanf("%d",&a[i]),b[i] = a[i];
		sort(b+1,b+1+n);
		m = unique(b+1,b+1+n) - b - 1;
		for(int i = 1;i <= n;i++) a[i] = lower_bound(b+1,b+1+m,a[i])- b;
		for(int i = 1;i <= n;i++) build(rt[i],1,m,a[i]);
		for(int i = 1;i < n;i++)
		{
			scanf("%d%d",&u,&v);
			G[u].push_back(v);
			G[v].push_back(u);
		}
		dfs(1,0);
		for(int i = 1;i <= n;i++)
		{
			printf("%lld",Ans[i]);
			if(i != n) printf(" ");
			else printf(" \n");
		}
		for(int i = 1;i <= n;i++) G[i].clear();
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值