P1351 [NOIP2014 提高組] 聯合權值

黑屿白發表於2024-07-31

原題連結

題解

樹形dp的想法,遞迴返回的是子樹的最大聯合權值以及聯合權值之和。

首先,根據題目意思可以知曉該無向圖構成的是一棵樹。

由樹形dp的遍歷可知,當我們來到 root結點時,其所有孩子結點的子樹 最大聯合權值 和 聯合權值之和 都已經知曉,我們只需要對其取 max 和 累加 即可。

but,上面是以root結點為中轉結點的情況,所以我們還要考慮root結點與 其父節點的父節點 相連形成的聯合權值的情況,進行特判即可。

code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const ll mod=10007;
ll head[N],Next[N<<1],to[N<<1],w[N],cnt=1;
struct node{
    ll MAX_val,sum;
    node(ll MAX_val,ll sum): MAX_val(MAX_val),sum(sum){}
};

void build(int from,int to_){
    Next[cnt]=head[from];
    to[cnt]=to_;
    head[from]=cnt++;
}

node dfs(int root,int f,int g){
    int more=w[root]*w[g]*2;
    node ans(more/2,0);
    ans.sum=(ans.sum+more)%mod;
     
    node x(0,0);
    ll max1=0,max2=0,val=0,power=0;
    for (int i=head[root];i>0;i=Next[i]){
        if (to[i]==f) continue;
        val+=w[to[i]];
        power+=w[to[i]]*w[to[i]];
        x=dfs(int(to[i]),root,f);
        ans.sum=(ans.sum+x.sum)%mod;
        ans.MAX_val=max(ans.MAX_val,x.MAX_val);
        if (w[to[i]]>max1) max1=w[to[i]];
        else if (w[to[i]]>max2) max2=w[to[i]];
    }
    if (max1*max2>ans.MAX_val)
        ans.MAX_val=max1*max2;
    ans.sum=(ans.sum+val*val-power)%mod;
    
    return ans;
}

int main(){
    int n;
    cin>>n;
    for (int i=1,u,v;i<n;i++){
        cin>>u>>v;
        build(u,v);
        build(v,u);
    }
    for (int i=1;i<=n;i++) cin>>w[i];
    
    node x=dfs(1,0,0);
    cout<<x.MAX_val<<" "<<x.sum<<endl;
    return 0;
}

相關文章