题目来源
洛谷P1351 联合权值
https://www.luogu.org/problemnew/show/P1351
思路
由于有n个点n-1条边 所以这个无向图可转化为一棵树
在树上距离为2的点的位置关系有两种
①距离他们的LCA距离均为1
② 其中一个点是另一个点的父节点的父节点
深搜 统计以每个节点为根节点的子树最浅(除根节点外)两层节点的权值和和最大值即可
注:这种方法求出的联合权值和是无序点对的 最后答案乘二即可
代码(C++)
#include <cstdio>
#include <bitset>
#define N 200010
using namespace std;
bitset<N> g; const long long mod=10007;
struct tree{long long m1,m2,a2;}*root;
int n,cnt,u,v,he[N],en[2*N],ne[2*N];
long long wei[N],ans1=0,ans2=0;
tree *dfs(int pos);
inline void add();
int main()
{
scanf("%d",&n);
for(int i=1;i<n;++i)
scanf("%d%d",&u,&v),add();
for(int i=1;i<=n;++i)
scanf("%lld",&wei[i]);
root=dfs(1);
printf("%lld %lld",ans1,ans2*2%mod);
return 0;
}
tree *dfs(int pos)
{
tree *k=new tree(),*tem; g[pos]=1;
k->m1=wei[pos]; k->m2=0; k->a2=0;
for(int i=he[pos];i!=0;i=ne[i])
if(g[en[i]]==0)
{
tem=dfs(en[i]);
ans2=(ans2+tem->a2*k->m1)%mod;
if(tem->m2*k->m1>ans1)
ans1=tem->m2*k->m1;
ans2=(ans2+k->a2*tem->m1)%mod;
if(k->m2*tem->m1>ans1)
ans1=k->m2*tem->m1;
k->a2+=tem->m1;
if(tem->m1>k->m2)
k->m2=tem->m1;
}
return k;
}
inline void add()
{
en[++cnt]=v; ne[cnt]=he[u]; he[u]=cnt;
en[++cnt]=u; ne[cnt]=he[v]; he[v]=cnt;
}