【NOIP2014】联合权值 树上dp

题目描述 Description

无向连通图G 有n 个点,n - 1 条边。点从1 到n 依次编号,编号为 i 的点的权值为W i   ,每条边的长度均为1 。图上两点( u ,  v ) 的距离定义为u 点到v 点的最短距离。对于图G 上的点对( u, v) ,若它们的距离为2 ,则它们之间会产生Wu
×Wv 的联合权值。
请问图G 上所有可产生联合权值的有序点对中,联合权值最大的是多少?所有联合权值之和是多少?
输入输出格式 Input/output
输入格式:
输入文件名为link .in。
第一行包含1 个整数n 。
接下来n - 1 行,每行包含 2 个用空格隔开的正整数u 、v ,表示编号为 u 和编号为v 的点之间有边相连。
最后1 行,包含 n 个正整数,每两个正整数之间用一个空格隔开,其中第 i 个整数表示图G 上编号为i 的点的权值为W i 。
输出格式:
输出文件名为link .out 。
输出共1 行,包含2 个整数,之间用一个空格隔开,依次为图G 上联合权值的最大值
和所有联合权值之和。由于所有联合权值之和可能很大, 输出它时要对10007 取余。
输入样例:
5  
1 2  
2 3
3 4  
4 5  
1 5 2 3 10

输出样例:
20 74
 
思路:
 
一般的做法,可能采用floyd这种鬼畜的最短路来慢慢搞,当然这样做是会完美T掉的!
所以我们要采取机智的方法,距离为2的话,我们就枚举中间的点,这样,他的任意两个儿子的距离就是2~\(≧▽≦)/~啦啦啦
第一问答案,就是枚举每个点的第一大和第二大的儿子,相乘求最大就好
第二问答案我们得化简一下,比如有a有三个儿子,那么答案就是cb,cd,bd,然后稍微推广一下,就知道答案是 (( ∑儿子)^2-∑(儿子)^2)/2,然后利用前缀和思想维护一下,就好啦
~\(≧▽≦)/~啦啦啦
 
代码:
//qscqesze

#include <cstdio>

#include <cmath>

#include <cstring>

#include <ctime>

#include <iostream>

#include <algorithm>

#include <set>

#include <vector>

#include <sstream>

#include <queue>

#include <typeinfo>

#include <fstream>

#include <map>

typedef long long ll;

using namespace std;

//freopen("D.in","r",stdin);

//freopen("D.out","w",stdout);

#define sspeed ios_base::sync_with_stdio(0);cin.tie(0)

#define maxn 200001

#define mod 10007

#define eps 1e-9

const int inf=0x7fffffff;   //无限大

//**************************************************************************************



vector<int> point[maxn];

void add_edge(int a,int b)

{

    point[a].push_back(b);

    point[b].push_back(a);

}

ll h[maxn];

int main()

{

    int n,a,b;

    scanf("%d",&n);

    for(int i=0;i<n-1;i++)

    {

        scanf("%d%d",&a,&b);

        add_edge(a,b);

    }

    for(int i=1;i<=n;i++)

        scanf("%d",&h[i]);

    ll ans1=0,ans2=0;

    for(int i=1;i<=n;i++)

    {

        ll max_num=0,sum=0;

        for(int j=0;j<point[i].size();j++)

        {

            int now=point[i][j];

            ans1=max(ans1,max_num*h[now]);

            ans2=(ans2+sum*h[now]+mod)%mod;

            max_num=max(max_num,h[now]);

            sum+=h[now];

        }

    }

    cout<<ans1<<" "<<(ans2*2+mod)%mod<<endl;

}

 

 

你可能感兴趣的:(IP)