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

探讨了如何通过线段树合并优化风暴兵的信息传递过程,减少信息上传的总延迟时间,并提供了一个具体的实现方案。
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 ttunits 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 (1n1051≤n≤105) in the first line, denoting the size of the tree. 

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

The following n1n−1 lines describe the edges of the tree. Each line contains two integers u,vu,v (1u,vn1≤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
分析:题意很迷,不过大概就是每棵子树的根都需要上传这棵子树上的所有信息,对于每棵子树我们只要把它要上传的信息排个序上传就可以了,现在显然不能暴力搞,考虑线段树合并,线段树维护三个信息,区间答案,区间和,还有区间有几个数,区间和和区间个数可以直接相加,区间答案就是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();
	}
}






评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值