HDU-2196 -Computer &&CodeForces - 1084D- The Fair Nut and the Best Path(树形dp)

HDU-2196题目链接

由于题目太长,扔到最后了先,这道题就是先给你几个电脑,告诉你哪些电脑是联通的,以及互相联通的电脑之间电线的长度,让你找到每一台电脑出发,它所能走的最远的路,乍一看,这不是树的直径问题吗,只不过是往上往下需要两个dfs,有点复杂好像,我们学长把这道题挂在了树形dp专题上,肯定有他的用意,那就用树形dp来做吧。

我们设dp[x]为经过边x所能到达的最远距离

如图所示,假设我们从点2开始,第一遍搜索我们便可以遍历到边 2、3、5、7所能到达的最远距离dp[i],然后我们遍历节点4的时候就可以使用上一步的结果,节省了搜索的次数,而离节点,4最远的距离则变成了max(dp[2]+dis(6),dp[7]+dis(6),dp[3]+dis(6),dp[9],dp[11])刷新结果即可,这样以后再遍历的时候就不用那么费事了

#define ll long long

#这里存图用的是链式向前星
struct node{
	ll to,val;
	ll next;
}pp[mm<<1];

#下面是核心dfs
ll dfs(ll x,ll pre){
	ll res=0;
	for(ll i=head[x];i!=-1;i=pp[i].next){
		ll t=pp[i].to;
		if(t==pre)continue;
		if(!dp[i])
			dp[i]=dfs(t,x)+pp[i].val;//遍历寻找经过这条边能到达的最远距离
		res=max(res,dp[i]);
	}
	return res;
}

 

还有要注意的就是这道题的输入有点坑人

→→→点击这里即可获得AC代←←←

 

 

我们再看一下下一道题,题目链接:

CodeForces - 1084D- The Fair Nut and the Best Path

这道题则是上一道题的进阶版本

你可以开车了,在许多个城市,每个城市的加油站都有加油的上限,而经历每一条路都会消耗这条路的长度的汽油,让你任意找一个起点,任意选择一条路,使得走过之后你的车里的油最多,当然,没经过一次车站的时候你都会把油加满先,抽象点来说就是:每个点有正权值ai,每条边有负权值wi,你可以随意选择一条路径,使得这条路径的总权值最大,要求每个点每条边至多都只能走一次。

我的脑袋瓜子不好用啊,只能请教身边的大佬,摸了一晚上也没摸出什么道道来,真心难受~_~

不过还好,我在那一遍遍的模拟,终于弄懂了那么一点点

我们仍旧是先设个dp数组dp[u]表示以u为根的子树中,以u为起点所能获得的最大值

先考虑以u为根节点的子树,
1.u是起点,那么ans就是u在子树中所能获得的最大价值
2.u是转折点,那么ans就是u在子树中获得的最大价值与次大价值之和

再就是考虑u通过父亲所能获得的最大价值与u在子树中所能获得的最大价值之和
这就类似树的直径问题
但是这道题只求一个最大值,可以看到 u通过父亲fa所能获得的最大价值与u在子树中所能获得的最大价值之和 
其实已经被以fa为起点在子树中所能获得的最大价值 所包括

那么就只需要考虑维护   直线式最值  和  本身价值 + 最大子节点价值 + 次大子节点价值

菜菜的我只能去膜拜大佬,这里有一篇讲的炒鸡详细的大佬版博客,我就不再多说了,先膜再说  Orz   https://blog.csdn.net/weixin_44757834/article/details/99542935

下面是我卑微的代码。。。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#define ll long long
using namespace std;
const ll inf=0x3f3f3f3f;
const ll mm=3e5+5; 

ll n;
ll x,y,z;
ll res;
ll w[mm];
ll dp[mm];//dp[i]为以i为根的子树中,以i为起点所能获得的最大值 
ll head[mm];
ll book[mm];

struct node{
	ll from,to;
	ll len;
	ll next;
}pp[mm<<1];
ll cnt=0;
void add(ll x,ll y,ll z){
	pp[cnt].from=x;
	pp[cnt].to=y;
	pp[cnt].len=z;
	pp[cnt].next=head[x];
	head[x]=cnt++;
}

void dfs(ll x,ll pre){//当前节点,前驱节点 
	dp[x]=w[x];
	res=max(res,dp[x]);//
	for(ll i=head[x];i!=-1;i=pp[i].next){
		ll next=pp[i].to;
		if(next==pre)continue;
		dfs(next,x);//
		res=max(res,dp[x]+dp[next]-pp[i].len);//维护直线式的最值
		dp[x]=max(dp[x],w[x]+dp[next]-pp[i].len);//当所有子节点都遍历过了,最大值和次大值必定进行了一次sum(重点)
	}
}

int main()
{
	cin>>n;
	memset(head,-1,sizeof(head));
	for(ll i=1;i<=n;i++)
		cin>>w[i];
	for(ll i=1;i<n;i++){
		cin>>x>>y>>z;
		add(x,y,z);
		add(y,x,z);
	}
	
	dfs(1,-1);
	cout<<res<<endl;
		
	return 0;
}

好了,最后的最后,添加上这两道题目的大字~_~

Computer

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 38018    Accepted Submission(s): 6771


 

Problem Description

A school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information.



Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.

 

Input

Input file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.

 

Output

For each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).

 

Sample Input

 

5

1 1

2 1

3 1

1 1

 

Sample Output

3

2

3

4

4

 

进阶版的汽车加油:

The Fair Nut and the Best Path  CodeForces - 1084D

The Fair Nut is going to travel to the Tree Country, in which there are nn cities. Most of the land of this country is covered by forest. Furthermore, the local road system forms a tree (connected graph without cycles). Nut wants to rent a car in the city uu and go by a simple path to city vv. He hasn't determined the path, so it's time to do it. Note that chosen path can consist of only one vertex.

A filling station is located in every city. Because of strange law, Nut can buy only wiwi liters of gasoline in the ii-th city. We can assume, that he has infinite money. Each road has a length, and as soon as Nut drives through this road, the amount of gasoline decreases by length. Of course, Nut can't choose a path, which consists of roads, where he runs out of gasoline. He can buy gasoline in every visited city, even in the first and the last.

He also wants to find the maximum amount of gasoline that he can have at the end of the path. Help him: count it.

Input

The first line contains a single integer nn (1≤n≤3⋅1051≤n≤3⋅105) — the number of cities.

The second line contains nn integers w1,w2,…,wnw1,w2,…,wn (0≤wi≤1090≤wi≤109) — the maximum amounts of liters of gasoline that Nut can buy in cities.

Each of the next n−1n−1 lines describes road and contains three integers uu, vv, cc (1≤u,v≤n1≤u,v≤n, 1≤c≤1091≤c≤109, u≠vu≠v), where uu and vv — cities that are connected by this road and cc — its length.

It is guaranteed that graph of road connectivity is a tree.

Output

Print one number — the maximum amount of gasoline that he can have at the end of the path.

Examples

Input

3
1 3 3
1 2 2
1 3 2

Output

3

Input

5
6 3 2 5 0
1 2 10
2 3 3
2 4 1
1 5 1

Output

7

Note

The optimal way in the first example is 2→1→32→1→3.

The optimal way in the second example is 2→42→4.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值