宝藏

宝藏
【问题描述】
一棵 个点的树,到达一个点会获得这个点上的宝藏,每个宝藏都有一定的
价值。经过每条边需要支付一定的过路费。每个点只有一个宝藏,但过路费每次
都要交。求从每个点出发能得到的最大收益。
【输入文件】
输入文件为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]uu

Max[u]u

D[u]Max[u]

Max1[u]

dfs2

tree[u]uu

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值