习题:Alternating Tree(树DP)
题目
思路
我们考虑即使是枚举路径也是\(n^2\)级别的复杂度
所以我们反过来考虑每一个点的贡献是什么
情况1
这个点直接连向儿子节点
此时的计算即为\(siz[u]*val[u]\)
情况2
考虑子树内的一条链跨过他到了子树内的另一点
这个时候也是比较好算的,我们只需要知道每一个点到他的时候,
这个点是-1还是1,这个用两个dp数组可以解决
情况3
考虑从子树外的一点经过他到子树内的一定
这种情况与情况二比较类似,dp基本上是一样的
代码
#include<iostream>
#include<vector>
using namespace std;
const int mod=1e9+7;
int n;
long long val[200005],siz[200005];
long long dp1[200005],f1[200005];//子树内奇数/偶数
long long dp2[200005],f2[200005];//子树外奇数/偶数
long long ans;
vector<int> g[200005];
void dfs1(int u,int fa)
{
siz[u]=1;
f1[u]=1;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa)
{
dfs1(v,u);
dp1[u]+=f1[v];
f1[u]+=dp1[v];
siz[u]+=siz[v];
}
}
}
void dfs2(int u,int fa)
{
long long s1=0,s2=0;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa)
{
s1+=dp1[v];
s2+=f1[v];
}
}
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa)
{
dp2[v]=f2[u]+s1-dp1[v]+1;
f2[v]=dp2[u]+s2-f1[v];
dfs2(v,u);
}
}
}
void dfs3(int u,int fa)
{
ans=(ans+(f1[u]-dp1[u])*val[u]%mod*(n-siz[u]+1)%mod)%mod;
ans=(ans+(siz[u]-1)*val[u]%mod)%mod;
ans=(ans+(f2[u]-dp2[u])*siz[u]%mod*val[u]%mod)%mod;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=fa)
{
ans=(ans+(dp1[v]-f1[v])*(siz[u]-siz[v]-1)%mod*val[u]%mod)%mod;
dfs3(v,u);
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++)
cin>>val[i];
for(int i=1,u,v;i<n;i++)
{
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
dfs1(1,0);
dfs2(1,0);
dfs3(1,0);
cout<<(ans+mod)%mod;
return 0;
}

浙公网安备 33010602011771号