题意
从树上选 个连通块,使得 尽可能大,在一样大的基础上,让 尽可能大
题解
我们考虑,显然是倒序排集合,如果说你已经选了
个,要选第
。
比较大小,因为
令
,你会发现
,而这是已知条件,所以只选一个即是最优的。
但是
要越大越好,所以要求选多个最大值集合。
求以
为根节点,必须取该点往下的最大权值(同一集合)
显然有:
得到最大值之和,再跑一遍 ,每次和最大值相同是, ,令当前 等于负无穷,然后回溯。即能保证不会重叠。
#include<bits/stdc++.h>
#define FOR(i,l,r) for(int i=l;i<=r;i++)
#define sf(x) scanf("%d",&x)
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn = 405000;
int n,A[maxn];
vector<int>G[maxn];
ll dp[maxn],ans=-inf,k;
void dfs1(int u,int f){
dp[u]=A[u];
for(auto v:G[u]){
if(v==f)continue;
dfs1(v,u);
dp[u]+=max(dp[v],1ll*0);
}
ans=max(ans,dp[u]);
}
void dfs2(int u,int f){
dp[u]=A[u];
for(auto v:G[u]){
if(v==f)continue;
dfs2(v,u);
dp[u]+=max(dp[v],1ll*0);
}
if(dp[u]==ans){
k++;
dp[u]=-inf;
}
}
int main(){
cin>>n;
FOR(i,1,n)dp[i]=-inf;
FOR(i,1,n)scanf("%d",&A[i]);
FOR(i,1,n-1){
int u,v;
scanf("%d%d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs1(1,-1);
dfs2(1,-1);
cout<<ans*k<<" "<<k<<endl;
}