题目:http://codeforces.com/contest/1092/problem/F
分析:拿第一个样例来说,先维护f,s两个数组,f[x]表示以x为根的子树的所有结点到x的带权路径长度和,s[x]表示以x为根的子树所有结点包括x结点的权值和。假设y是x结点的儿子,那么把以y为根的子树当作一个整体,该整体内部的带权路径长度和(内部)+该整体所有结点权值和(外部)即等于以y为根的子树对x产生的带权路径长度和的贡献。
比如图中x=1,y=5,以y为根的子树的所有结点有6,7,8号,到y(5号)结点的WPL和为1*1+6*1+5*1=12,即f[5]=12,而以y为根的子树所有结点权值和为10+1+6+5=22,即s[5]=22,那么以5号结点为根的子树对1号结点产生的WPL贡献为f[5]+s[5]=34,这样可以求出以1号结点为根的子树的WPL=47,然后关键是要选一个根结点使以该根节点为根的子树的WPL最大。
关键步骤:比如刚刚已经求了以1号结点为根的子树的WPL,然后现子求它的邻接点的,此时要对所扩展的邻接点的f,s实施间接更新,具体看代码
AC code:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+2;
typedef long long ll;
int val[maxn];
ll _max;
ll f[maxn],s[maxn];
vector<int>edge[maxn];
void dfs(int u,int fa)
{
s[u]=val[u];
f[u]=0;
for(int i=0;i<edge[u].size();i++){
int v=edge[u][i];
if(v!=fa){
dfs(v,u);
f[u]+=f[v]+s[v];
s[u]+=s[v];
}
}
}
void dfs(int u,int fa,ll updates,ll updatef)///updates,updatef分别表示对s,f数组来间接更新
{
_max=max(_max,f[u]+updatef);
for(int i=0;i<edge[u].size();i++){
int v=edge[u][i];
if(v!=fa){
ll ups=updates+s[u]-s[v];//s数组的间接更新
dfs(v,u,ups,updatef+f[u]-f[v]-s[v]+ups);
}
}
}
int main()
{
int n,x,y;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
}
for(int i=1;i<=n-1;i++){
scanf("%d%d",&x,&y);
edge[x].push_back(y);
edge[y].push_back(x);
}
_max=0;
dfs(1,0);
dfs(1,0,0,0);
printf("%lld\n",_max);
}
法二:
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+2;
typedef long long ll;
ll val[maxn];
ll sum;
ll _max;
vector<int>edge[maxn];
void dfs(int u,int fa,int dp)///求出以1号结点为根结点的WPL和
{
for(int i=0;i<edge[u].size();i++){
int v=edge[u][i];
if(v!=fa){
sum+=val[v]*dp;
dfs(v,u,dp+1);
val[u]+=val[v];
}
}
}
void dfs2(int u,int fa,ll sum)
{
if(u!=1) sum=val[1]-val[u]+sum-val[u];///算出以其他结点为根结点的WPL和
_max=max(_max,sum); ///,可由其前驱结点算的WPL来算出
for(int i=0;i<edge[u].size();i++){
int v=edge[u][i];
if(v!=fa) dfs2(v,u,sum);
}
}
int main()
{
int n,x,y;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%lld",&val[i]);
}
for(int i=1;i<=n-1;i++){
scanf("%d%d",&x,&y);
edge[x].push_back(y);
edge[y].push_back(x);
}
_max=0;
sum=0;
dfs(1,0,1);
dfs2(1,0,sum);
printf("%lld\n",_max);
return 0;
}