0x10 题目链接
p1351
0x20 题目
0x21 Tag
图论,数学
0x22 题目描述

0x30 思路与算法
当然最大联合权值比较好求, 只需要求出当前节点cur四周点的最大值和次大值。
 对于联合权值之和, 假设当前节点cur所连接的点的权值为
    
     
      
       
        
         v
        
        
         1
        
       
       
        ,
       
       
        
         v
        
        
         2
        
       
       
        ,
       
       
        ⋯
       
      
      
       v_1,v_2,⋯
      
     
    v1,v2,⋯那么节点cur对权值之和产生的贡献为:
     
      
       
        
         W
        
        
         =
        
        
         
          ∑
         
         
          
           v
          
          
           i
          
         
        
        
         
          ∑
         
         
          
           v
          
          
           j
          
         
        
        
         
          v
         
         
          i
         
        
        
         
          v
         
         
          j
         
        
       
       
        W=\sum_{v_i}\sum_{v_j}v_iv_j
       
      
     W=vi∑vj∑vivj
     
      
       
        
         =
        
        
         
          ∑
         
         
          
           v
          
          
           i
          
         
        
        
         
          v
         
         
          i
         
        
        
         
          ∑
         
         
          
           
            v
           
           
            j
           
          
          
           !
          
          
           =
          
          
           
            v
           
           
            i
           
          
         
        
        
         
          v
         
         
          j
         
        
       
       
        =\sum_{v_i}v_i\sum_{v_j!=v_i}v_j
       
      
     =vi∑vivj!=vi∑vj
     
      
       
        
         =
        
        
         
          ∑
         
         
          
           v
          
          
           i
          
         
        
        
         
          v
         
         
          i
         
        
        
         [
        
        
         (
        
        
         
          ∑
         
         
          
           v
          
          
           j
          
         
        
        
         
          v
         
         
          j
         
        
        
         )
        
        
         −
        
        
         
          v
         
         
          i
         
        
        
         ]
        
       
       
        =\sum_{v_i}v_i[(\sum_{v_j}v_j)-v_i]
       
      
     =vi∑vi[(vj∑vj)−vi]
     
      
       
        
         =
        
        
         (
        
        
         
          ∑
         
         
          
           v
          
          
           i
          
         
        
        
         
          v
         
         
          i
         
        
        
         
          )
         
         
          2
         
        
        
         −
        
        
         
          ∑
         
         
          
           v
          
          
           i
          
         
        
        
         
          v
         
         
          i
         
         
          2
         
        
       
       
        =(\sum_{v_i}v_i)^2-\sum_{v_i}v_i^2
       
      
     =(vi∑vi)2−vi∑vi2
 将每个节点的W加和即得联合权值之和。
0x40 代码
0x41 实现细节
声明
const int MAXN=2e5+5;
int ans1=0,ans2=0;
int a[MAXN];
int n;
这里ans1记录联合权值最大值,ans2记录联合权值之和。n是节点数,a数组存储节点权值。
 存图
struct Edge
{
    int to, w, next;
}edges[MAXN<<1];
int heads[MAXN], cnt; // cnt为当前边的编号
inline void add(int from, int to, int w = 1)
{
    edges[++cnt].w = w;    //新增一条编号为cnt+1的边,边权为w
    edges[cnt].to = to;    //该边的终点为to
    edges[cnt].next = heads[from];  //把下一条边,设置为当前起点的第一条边
    heads[from] = cnt;  //该边成为当前起点新的第一条边
}
由于不知道根节点,存一个无向图方便dfs
 DFS
void dfs(int cur,int fath)
{
    if(cur>n) return;
    int m1=0,m2=0;
    int sq=0,sum=0;
    for (int eg = heads[cur]; eg != 0; eg = edges[eg].next)
    {
        int to=edges[eg].to;
        if(to!=fath) dfs(to,cur);
        if(a[to]>m2)
        {
            if(a[to]>m1)
            {
                m2=m1;
                m1=a[to];
            }
            else m2=a[to];
        }
        sq+=((a[to]%MOD)*(a[to]%MOD))%MOD;
        sq%=MOD;
        sum+=a[to]%MOD;
        sum%=MOD;
    }
    ans1=max(ans1,m1*m2);
    ans2+=((((sum%MOD)*(sum%MOD))%MOD-sq%MOD)+MOD)%MOD;
    ans2%=MOD;
}
其中的if(cur>n) return;与if(to!=fath) dfs(to,cur);防止反复DFS。两个if判断最小值和次小值。注意这里的MOD,做减法要在最后加MOD,如果开了long long 就不用每一项都模了。
0x42 完整代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll MOD = 10007;
const ll INF = 0x3f3f3f3f;
// <------------------------------->
#define endl "\n"
#define IOS ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
#define HACK freopen("test.in", "r", stdin);freopen("test.out", "w", stdout);
#define RT double rtime = 1.0 * clock() / CLOCKS_PER_SEC;cout<<"\nRuntime: "<<rtime<< " s.\n";
#define debug(x) cout<<"target is "<<x<<endl
#define debug_arr(arr) for(auto x:arr) cout<<x<<" "; cout<<"\n";
// <------------------------------->
const int MAXN=2e5+5;
int ans1=0,ans2=0;
int a[MAXN];
int n;
struct Edge
{
    int to, w, next;
}edges[MAXN<<1];
int heads[MAXN], cnt; // cnt为当前边的编号
inline void add(int from, int to, int w = 1)
{
    edges[++cnt].w = w;    //新增一条编号为cnt+1的边,边权为w
    edges[cnt].to = to;    //该边的终点为to
    edges[cnt].next = heads[from];  //把下一条边,设置为当前起点的第一条边
    heads[from] = cnt;  //该边成为当前起点新的第一条边
}
//<------------------------------->
void dfs(int cur,int fath)
{
    if(cur>n) return;
    int m1=0,m2=0;
    int sq=0,sum=0;
    for (int eg = heads[cur]; eg != 0; eg = edges[eg].next)
    {
        int to=edges[eg].to;
        if(to!=fath) dfs(to,cur);
        if(a[to]>m2)
        {
            if(a[to]>m1)
            {
                m2=m1;
                m1=a[to];
            }
            else m2=a[to];
        }
        sq+=((a[to]%MOD)*(a[to]%MOD))%MOD;
        sq%=MOD;
        sum+=a[to]%MOD;
        sum%=MOD;
    }
    ans1=max(ans1,m1*m2);
    ans2+=((((sum%MOD)*(sum%MOD))%MOD-sq%MOD)+MOD)%MOD;
    ans2%=MOD;
}
int main()
{
    IOS;
    #ifdef LOCAL_JUDGE
    HACK;
    #endif
    
    cin>>n;
    for(int i=1;i<=n-1;++i)
    {
        int u,v;
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    for(int i=1;i<=n;++i)
        cin>>a[i];
    dfs(1,0);
    cout<<ans1<<" "<<ans2;
    
    #ifdef LOCAL_JUDGE
    RT;
    #endif
    return 0;
}










