Magic boy Bi Luo with his excited tree
Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 823 Accepted Submission(s): 222
Problem Description
Bi Luo is a magic boy, he also has a migic tree, the tree has
N
nodes , in each node , there is a treasure, it's value is
V[i]
, and for each edge, there is a cost
C[i]
, which means every time you pass the edge
i
, you need to pay
C[i]
.
You may attention that every V[i] can be taken only once, but for some C[i] , you may cost severial times.
Now, Bi Luo define ans[i] as the most value can Bi Luo gets if Bi Luo starts at node i .
Bi Luo is also an excited boy, now he wants to know every ans[i] , can you help him?
You may attention that every V[i] can be taken only once, but for some C[i] , you may cost severial times.
Now, Bi Luo define ans[i] as the most value can Bi Luo gets if Bi Luo starts at node i .
Bi Luo is also an excited boy, now he wants to know every ans[i] , can you help him?
Input
First line is a positive integer
T(T≤104)
, represents there are
T
test cases.
Four each test:
The first line contain an integer N (N≤105) .
The next line contains N integers V[i] , which means the treasure’s value of node i(1≤V[i]≤104) .
For the next N−1 lines, each contains three integers u,v,c , which means node u and node v are connected by an edge, it's cost is c(1≤c≤104) .
You can assume that the sum of N will not exceed 106 .
Four each test:
The first line contain an integer N (N≤105) .
The next line contains N integers V[i] , which means the treasure’s value of node i(1≤V[i]≤104) .
For the next N−1 lines, each contains three integers u,v,c , which means node u and node v are connected by an edge, it's cost is c(1≤c≤104) .
You can assume that the sum of N will not exceed 106 .
Output
For the i-th test case , first output Case #i: in a single line , then output
N
lines , for the i-th line , output
ans[i]
in a single line.
Sample Input
1 5 4 1 7 7 7 1 2 6 1 3 1 2 4 8 3 5 2
Sample Output
Case #1: 15 10 14 9 15
这道题的题意就是给你一个树,每一个节点有一个收益,每条边每次经过都会有一个花费。问你从每个节点出发,最大的收益是多少。
这道题就是一个很明显的树形DP了,两个dfs,一个dfs是更新每个节点从当前节点出发回到原点的最大收益和不回到原点的最大收益,以及到达的位置。
第二个dfs是从父节点向下更新每个节点的答案。这个还是不难想的,就是细节有点多写起来有些烦。
AC代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int maxn=1e5+5;
int head[maxn],tot,val[maxn];
int w[maxn],bw[maxn],wid[maxn],ans[maxn];
/*
w表示当前回来的最大收益
bw表示当前走出去的最大收益
id表示做出去的最大收益的节点
*/
void init(){
memset(head,-1,sizeof(head));
tot=0;
}
struct Edge{
int from,to,next,cost;
Edge(){}
Edge(int from,int to,int cost,int next){
this->from=from;
this->to=to;
this->cost=cost;
this->next=next;
}
}e[maxn*2];
void add_edge(int u,int v,int c){
e[tot]=Edge(u,v,c,head[u]);
head[u]=tot++;
e[tot]=Edge(v,u,c,head[v]);
head[v]=tot++;
}
void dfs1(int u,int fa){
w[u]=val[u];
bw[u]=val[u];
wid[u]=0;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
dfs1(v,u);
int btemp=max(0,bw[v]-e[i].cost*2);//回来的收益
int temp=bw[u]+max(0,w[v]-e[i].cost);//不回来的收益
w[u]+=btemp;
bw[u]+=btemp;
if(w[u]<temp){
w[u]=temp;
wid[u]=v;
}
}
}
void dfs2(int u,int fa,int sum1,int sum2){
//sum1表示当前节点不回来的最大收益,sum2表示当前节点回来的最大收益
ans[u]=max(w[u]+sum2,bw[u]+sum1);
int W=w[u];
int BW=bw[u];
int Id=wid[u];
W+=sum2;
if(W<=BW+sum1){
W=BW+sum1;
Id=fa;
}
BW+=sum2;
for(int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==fa) continue;
if(v==Id){
int tmp1=sum1+val[u],tmp2=sum2+val[u];
for(int j=head[u];~j;j=e[j].next){
int vv=e[j].to;
if(vv==fa || v==vv) continue;
int tmp=max(0,bw[vv]-e[j].cost*2);
tmp1=max(tmp2+max(0,w[vv]-e[j].cost),tmp1+tmp);
tmp2+=tmp;
}
tmp1=max(0,tmp1-e[i].cost);
tmp2=max(0,tmp2-2*e[i].cost);
dfs2(v,u,tmp1,tmp2);
}
else{
int tmp=max(0,bw[v]-e[i].cost*2);
int tmp1=max(0,W-tmp-e[i].cost);
int tmp2=max(0,BW-tmp-e[i].cost*2);
dfs2(v,u,tmp1,tmp2);
}
}
}
int main(){
int n,t,icas=1;
scanf("%d",&t);
while(t--){
init();
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&val[i]);
for(int i=1;i<n;i++){
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
add_edge(u,v,c);
}
dfs1(1,-1);
dfs2(1,-1,0,0);
printf("Case #%d:\n", icas++);
for(int i = 1; i <= n; ++i)
printf("%d\n", ans[i]);
}
}