1. 程式人生 > >樹-P1351 聯合權值

樹-P1351 聯合權值

題目連結:
https://www.luogu.org/problemnew/show/P1351
看題解,還是一知半解,先紀錄一下,後續再搞。

在這裡插入圖片描述

/*
先看求聯合權值的和。稍稍對題意進行變形,即為:對每一個點,找到與它相連的所有點,那些點之間兩兩權值相乘,最後把所有乘積相加(並取餘,別忘了qwq)。
我們想象:每連上一條邊,便進行一次“操作”。定義一個數組S,用S[i]記錄第i個點周圍已經連上的點的權值之和。連上一條邊時,比方說從a點到b點,對這兩個點分別進行操作,拿a點舉例:
首先將b點的權值乘以已經連上a點的所有點的權值之和(就是S[a]),加到總結果sum上;然後把b點的權值加到S[a]上。
b點的操作同理。這樣的話,從第一條邊連到最後一條邊,sum累積了一半的聯合權值總和,x2便是正確答案。
(稍稍想想大概就是這麼回事吧...)
再看求最大值。類似地,定義一個數組M,用M[i]記錄第i個點周圍已經連上的點的權值的最大值。類似於上面的操作,每連上一條邊,分別更新相應的M[a]、M[b],以及全域性聯合權值的最大值ans。
最後...別忘開long long否則70分orz
*/

#include<iostream>
#define N 200010
#define mod 10007

using namespace std;
long long w[N],A[N],B[N],S[N],M[N],sum,ans;
int n;
int main()
{
    cin>>n;
    for(int i=1;i<n;i++)   cin>>A[i]>>B[i];
    for(int i=1;i<=n;i++)   cin>>w[i];
    for(int i=1;i<n;i++)
    {
        int ta=A[i],tb=B[i];
        ans=max(ans,M[ta]*w[tb]);
        M[ta]=max(M[ta],w[tb]);//M[i]記錄第i個點周圍已經連上的點的權值的最大值
        sum=(sum+S[ta]*w[tb])%mod;
        S[ta]+=w[tb];//S[i]記錄第i個點周圍已經連上的點的權值之和
        
        ans=max(ans,M[tb]*w[ta]);
        M[tb]=max(M[tb],w[ta]);
        sum=(sum+S[tb]*w[ta])%mod;
        S[tb]+=w[ta];
    }
    cout<<ans<<" "<<(sum*2)%mod;
    return 0;
}