transaction transaction transaction
Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 132768/132768 K (Java/Others)Total Submission(s): 147 Accepted Submission(s): 67
As we know, the price of this book was different in each city. It is ai yuan in it city. Kelukin will take taxi, whose price is 1yuan per km and this fare cannot be ignored.
There are n−1 roads connecting n cities. Kelukin can choose any city to start his travel. He want to know the maximum money he can get.
For each test case:
first line contains an integer n (2≤n≤100000) means the number of cities;
second line contains n numbers, the ith number means the prices in ith city; (1≤Price≤10000)
then follows n−1 lines, each contains three numbers x, y and z which means there exists a road between x and y, the distance is zkm (1≤z≤1000).
1 4 10 40 15 30 1 2 30 1 3 2 3 4 10
8
思路:也就是说找两个点,大的点减小的点再减中间路径权值,找最大值
我们就只需要考虑每个点到它的子树里的最大值,从叶子节点一直找到根节点就可以了
所以是一个状态的转移
1.在叶子节点u的时候,它的子树就是有它本身,所以它卖书的最小花费就是 val[u] ,而卖书的最大价值也是 val[u]
所以叶子节点的答案就是 最大卖价 - 最小花费 = 0
2.向上回溯到它的父亲节点 u ,此刻叶子节点是 v , u v 间的距离是 w ,那么如果在 u 点买书和卖书,最小话费和最大价值都是 val[u] ,所以就要从前状态找更小花费和更大价值,如果 u 点的花费 < v 点花费 + 路费 w,那么自然是在u点买划算一些,而卖书自然的话,如果 u 的价格 > v点价格 - 路费 w 的话,就应该在 u 点卖,因为 u 点要么做买书位置,要么做卖书位置, 或者都不做,都不做的时候答案不会更新。
3. dp[ i ] [ j ] 中 , i 表示某点下标, j = 1表示该点卖书的最大值,j = 0 表示该点买书的最小值,然后每次都把最小状态赋值给它,父亲节点就能通过儿子节点的状态完整整个子树里的最优解了。
dp[i][0] = min(dp[i][0],dp[v][0] + w); 表示该点更新为最小花费
dp[i][1] = max(dp[i][1],dp[v][1] - w); 表示该点更新为最大价值
有可能同时更新为 dp[v][0] + w,和 dp[v][1] - w,但是答案不会更新为更大,因为此时会减2次 w,但是这个状态是需要保留的,因为更上方的点,到达 v 点的时候距离都得多上这一条 w,所以它是没有错的
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
#define maxn 100005
#define ll long long
#define mem(a,x) memset(a,x,sizeof(a))
const ll inf = (1ll) << 60;
struct node{
int v,w;
node(int v_,int w_) : v(v_),w(w_){}
};
int dp[maxn][2];
int val[maxn];
vector<node>vec[maxn];
int n,ans;
void add(int u,int v,int w){
vec[u].push_back(node(v,w));
}
void treedp(int u,int pre){
dp[u][0] = dp[u][1] = val[u];
int sz = vec[u].size();
for(int i = 0;i < sz;i++){
int v = vec[u][i].v;
int w = vec[u][i].w;
if(v == pre)
continue;
treedp(v,u);
dp[u][0] = min(dp[u][0],dp[v][0] + w);
dp[u][1] = max(dp[u][1],dp[v][1] - w);
}
ans = max(ans,dp[u][1] - dp[u][0]);
}
int main(){
int u,v,w,t;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(int i = 1;i <= n;i++){
scanf("%d",&val[i]);
vec[i].clear();
}
for(int i = 1;i < n;i++){
scanf("%d %d %d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
ans = 0;
treedp(1,-1);
printf("%d\n",ans);
}
}