宝藏
【问题描述】
一棵 个点的树,到达一个点会获得这个点上的宝藏,每个宝藏都有一定的
价值。经过每条边需要支付一定的过路费。每个点只有一个宝藏,但过路费每次
都要交。求从每个点出发能得到的最大收益。
【输入文件】
输入文件为treasure.in。
第一行为一个正整数n。
接下来n-1行,每行三个整数x,y,z ,描述一条边的两个端点 x,y和过路费 。
最后一行n个数,表示每个点上宝藏的价值 ai。
【输出文件】
输出文件为treasure.out。
输出 行,每行一个数。第 行表示从 出发的最大收益。
【输入输出样例】
treasure.in
6
1 2 1
2 3 3
3 4 36
3 6 13
3 5 2
6 8 9 10 13 1
treasure.out
30
29
28
10
30
16
【数据规模和约定】
对于20%的数据,满足n<=10。
对于50%的数据,满足n<=1000。
对于100%的数据,满足1<=n<=300000,1<=z,a[i]<=100000。
乍看要处理回到自己和不回到自己,各种转移……
其实这道题可以转化为走路回到自己和再加上走一条不回头的路
dfs1中
tree[u]表示从u出发只走子树回到u的最大收益
Max[u]表示从u出发走子树中一条不回头的路的最大收益
D[u]记Max[u]走了哪一个儿子
Max1[u]记次大值
dfs2中
tree[u]更新后表示从u出发可以走所有路回到u的最大收益
Max[u]更新后表示从u出发可以走所有路中一条不回头的路的最大收益
Max1[u],D[u]更新后无用
#include<iostream>
#include<cstdio>
using namespace std;
#define ll long long
int num;
#define M 600005
#define W 300005
int vet[M],val[M],Next[M],hed[W],D[W],a[W];
ll Max[W],Max1[W],tree[W];
inline int read(){
int X=0,w=1; char ch=0;
while(ch<'0' || ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0' && ch<='9') X=(X<<3)+(X<<1)+ch-'0',ch=getchar();
return X*w;
}
void calc(int u,int MM,int v){
if (MM>Max[u]){
Max1[u]=Max[u];
Max[u]=MM;
D[u]=v;
return;
}
if (MM>Max1[u]){
Max1[u]=MM;
return;
}
}
void add(int u,int v,int x){
++num;
vet[num]=v;
val[num]=x;
Next[num]=hed[u];
hed[u]=num;
}
void dfs1(int u,int fa){
tree[u]=a[u];
for (int i=hed[u];i!=-1;i=Next[i]){
int v=vet[i];
if (v==fa) continue;
dfs1(v,u);
tree[u]+=max(0ll,tree[v]-val[i]-val[i]);
calc(u,Max[v]-val[i]+tree[v]-max(0ll,tree[v]-val[i]-val[i]),v);
}
}
void dfs2(int u,int fa){
for (int i=hed[u];i!=-1;i=Next[i]){
int v=vet[i];
if (v==fa) continue;
ll item=tree[u]-val[i]-val[i]-max(0ll,tree[v]-val[i]-val[i]);
tree[v]+=max(0ll,item);
item=min(item,0ll);
if (D[u]==v) calc(v,item+Max1[u]+val[i],u);
else calc(v,item+Max[u]+val[i],u);
dfs2(v,u);
}
}
int main(){
int n;
n=read();
num=0;
for (int i=1;i<=n;++i) hed[i]=-1;
for (int i=1;i<n;++i){
int x,y,z;
x=read();y=read();z=read();
add(x,y,z);
add(y,x,z);
}
for (int i=1;i<=n;++i) a[i]=read();
dfs1(1,0);
dfs2(1,0);
for (int i=1;i<=n;++i)
printf("%lld\n",tree[i]+Max[i]);
return 0;
}