首先题意很清楚了,就是找两颗不想关的子树,使其权值和最大。
这是一道树形dp,也是我做的第一道树形dp,非常有纪念意义,所以在这里写一下。
写法非常智障,说明自己姿势水平还是太低。
先贴代码。
#include<bits/stdc++.h>
using namespace std;
const int maxn=200000+10;
const long long INF=10000000000000000;//这里要设大一点因为题目数据很大
long long ans,max1,max2;
int n;
vector<int> G[maxn],B[maxn];//B用来临时存储,G中存的树要求是有序的,即一条边只加一次
long long value[maxn],sum[maxn],dp[maxn];
void dfs1(int x)//calculate the sum of the subtree of x,计算每个节点子树的权值和sum
{
sum[x]=value[x];
for(auto it:G[x])
{
dfs1(it);
sum[x]+=sum[it];
}
}
void dfs2(int x)//calculate the largest sum of sub-trees of x,计算每个节点i的后代(包括i)中,sum最大的,记作dp【i】
{
dp[x]=sum[x];
for(auto it:G[x])
{
dfs2(it);
dp[x]=max(dp[x],dp[it]);
}
}
void doit(long long &max1,long long &max2,long long x)//update max1 and max2,max1为最大,max2为次大,x为新接受的元素
{
if(x<=max2)
return ;
if(x>=max1)
{
max2=max1;
max1=x;
return ;
}
{
max2=x;
return ;
}
}
void dfs(int x,int fa)//瞎几把遍历,生成G
{
for(auto i:B[x])
{
if(i==fa)
continue;
G[x].push_back(i);
dfs(i,x);
}
}
int main(void)
{
int u,v;
cin>>n;
for(int i=1;i<=n;i++)
cin>>value[i];
for(int i=1;i<n;i++)
{
cin>>u>>v;
B[u].push_back(v);
B[v].push_back(u);
}//读入,暂时存着,因为给的节点关系是无序的,需要经过预处理,使得其有序
dfs(1,-1);//to ensure the father and child relation:G[u]=v then v is child of u
dfs1(1);
dfs2(1);
ans=-INF;
for(int i=1;i<=n;i++)
{
if(G[i].size()>=2)
{
max1=max(dp[G[i][0]],dp[G[i][1]]);//the largest
max2=min(dp[G[i][0]],dp[G[i][1]]);//the second largest
for(int j=2;j<G[i].size();j++)
{
doit(max1,max2,dp[G[i][j]]);
}
ans=max(ans,max1+max2);
}
else
continue;
}
if(ans==-INF)
cout<<"Impossible";
else
cout<<ans;
return 0;
}
这道题我的时间控制的不是很好,因为加了一个预处理,把树按照标准形式存到了G里。