列表

详情


NC207420. 点对最大值

描述

这里有一棵树,每个点和每条边都存在一个价值。对于树上点对的价值,包括点对的起点和终点以及路径上边权值之和,不包括路径上其他点值。
求这颗树上最大的点对价值为多少。点对至少需要两个点。

输入描述

输入t,代表有t组样例。每组样例第一行输入n,代表有n个点。接下来有n-1行,第i行有a[i]和b[i],代表a[i]节点与i节点存在一条边,且边的值为b[i],2<=i<=n。接下来一行有n个值c[j],代表每个节点j的价值,1<=j<=n。
(t<=10,n>1,n<1e6,a[i]<i,-500<=b[i]<=500,-500<=c[j]<=500)

输出描述

输出最大的点对价值

示例1

输入:

1
4
1  -2
1   2
1   3
2 -2 3 4

输出:

12

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 344ms, 内存消耗: 29772K, 提交时间: 2020-06-01 16:17:57

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int e[N<<2],ne[N<<2],w[N<<2],h[N<<2],idx;
int t,n,ans;
int f[N];
void add(int a,int b,int c)
{
	e[idx]=b;w[idx]=c;ne[idx]=h[a];h[a]=idx++;
}
void dfs(int u,int fa)
{
	for(int i=h[u];~i;i=ne[i])
	{
		int v=e[i];
		if(v==fa) continue;
		dfs(v,u);
		ans=max(ans,f[u]+f[v]+w[i]);
	//	cout<<ans<<endl;
		f[u]=max(f[u],f[v]+w[i]);
	}
}
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		idx=0;
		memset(h,-1,sizeof h);
		ans=-0x3f3f3f3f;
		for(int i=2,u,c;i<=n;i++)
		{
			scanf("%d %d",&u,&c);
			add(u,i,c);
			add(i,u,c);
		}
		for(int i=1;i<=n;i++) scanf("%d",&f[i]); 
		dfs(1,-1);
		cout<<ans<<endl;
	}
	return 0;
	
	
}

C++11(clang++ 3.9) 解法, 执行用时: 640ms, 内存消耗: 94792K, 提交时间: 2020-05-31 23:20:39

#include<bits/stdc++.h>
using namespace std;

int ans,DP[1000005];
vector<int>R[1000005],W[1000005];
void DFS(int x,int fa)
{
	int i,j,m1=DP[x],m2=-2e9;
	for(i=0;i<R[x].size();i++)
	{
		j=R[x][i];
		if(j==fa)continue;
		DFS(j,x),m2=max(m2,DP[j]+W[x][i]);
		if(m1<m2)swap(m1,m2);
	}
	DP[x]=m1,ans=max(ans,m1+m2);
}
int main()
{
    int i,j,k,n,t; 
    scanf("%d",&t);
    while(t--)
    {
    	scanf("%d",&n),ans=-2e9;
    	for(i=1;i<=n;i++)R[i].clear(),W[i].clear();
    	for(i=2;i<=n;i++)
    	{
    		scanf("%d%d",&j,&k);
			R[i].push_back(j),R[j].push_back(i);
			W[i].push_back(k),W[j].push_back(k);
		}
		for(i=1;i<=n;i++)scanf("%d",&DP[i]);
		DFS(1,0);
		printf("%d\n",ans);
	}
}

上一题