洛谷 P1351 [NOIP2014 提高组] 联合权值(dp)

传送门


解题思路

先遍历一遍树,求出size[u](节点u的所有相邻节点的点权和),和图中联合权值的最大值。

如何求最大值?

求出每个点相连的点的第一大和第二大点权,相乘后与ans取max。

再求和:

再遍历一遍树,对于每个点u,答案加上w[u]*(size[v]-w[u])。

AC代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<iomanip>
 5 #include<cmath>
 6 using namespace std;
 7 const int maxn=200005;
 8 const int mod=10007;
 9 int n,p[maxn],cnt,w[maxn],fa[maxn];
10 long long ans,size[maxn];
11 struct node{
12     int v,next;
13 }e[maxn*2];
14 void insert(int u,int v){
15     cnt++;
16     e[cnt].v=v;
17     e[cnt].next=p[u];
18     p[u]=cnt;
19 }
20 void dfs(int u,int f){
21     long long max1=0,max2=0;
22     fa[u]=f;
23     for(int i=p[u];i!=-1;i=e[i].next){
24         if(e[i].v!=f){
25             dfs(e[i].v,u);
26         }
27         size[u]+=w[e[i].v];
28         if(w[e[i].v]>max2) max2=w[e[i].v];
29         if(max2>max1) swap(max2,max1);
30     }
31     ans=max(ans,max1*max2); 
32 }
33 void dfs2(int u){
34     for(int i=p[u];i!=-1;i=e[i].next){
35         if(e[i].v!=fa[u]) dfs2(e[i].v);
36         ans+=w[u]*(size[e[i].v]-w[u]);
37     }
38 }
39 int main(){
40     memset(p,-1,sizeof(p));
41     cin>>n;
42     for(int i=1;i<n;i++){
43         int u,v;
44         scanf("%d%d",&u,&v);
45         insert(u,v);
46         insert(v,u);
47     }
48     for(int i=1;i<=n;i++) scanf("%d",&w[i]);
49     dfs(1,-1);
50     cout<<ans<<" ";
51     ans=0;
52     dfs2(1);
53     cout<<ans%mod;
54     return 0;
55 }

 

posted @ 2021-02-22 11:50  尹昱钦  阅读(79)  评论(0编辑  收藏  举报