P3047 [USACO12FEB]Nearby Cows G
P3047 [USACO12FEB]Nearby Cows G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
树上思维好题
这道题不是树形dp,但是我们要用树形dp的思维来做这题.
首先我们令:dp[x][i]为在x的子树中,与x不超过i距离节点的权值之和。
显然这是很容易求的
void dfs1(int x,int fa) { dp[x][0]=a[x]; for(auto v:g[x]) { if(v==fa) continue; dfs1(v,x); } for(int i=1;i<=k;i++) { dp[x][i]=a[x]; for(auto v:g[x]) { if(v==fa) continue; dp[x][i]+=dp[v][i-1]; } } }
接着我们令:f[x][i]为在与x不超过i距离节点的权值之和
以1作为1号节点,1为2的父节点。上面是特地让图好看一些
首先有f[1][i]=dp[1][i],因为i为根节点
现在求与2节点不超过距离为2的节点权值和f[2][2],主要便是求不属于2节点子树的点。
对于不是2节点子树的点,便是包括在与1节点距离不超过1的点(9,7,8,2),这部分是f[1][1].
但是与1节点距离不超过1的点还包括 2节点 这种不合理点,这不合理部分是dp[1][1]还是dp[2][0]?显然dp[2][0](2),dp[1][1](9,7,8,2).
所以:f[2][2]=dp[2][2]+(f[1][1]-dp[2][0]);
则:if(i>=2) f[v][i]=dp[v][i]+(f[v][i-1]-dp[v][i-2])
if(i==1) f[v][1]=dp[v][i]+a[x];
if(i==0) f[v][0]=d[v][0];
void dfs2(int x,int fa) { if(x==1) for(int i=1;i<=k;i++) f[1][i]=dp[1][i]; for(auto v:g[x]) { if(v==fa) continue; f[v][0]=dp[v][0]; f[v][1]=dp[v][1]+a[x]; for(int i=2;i<=k;i++) f[v][i]=dp[v][i]+(f[x][i-1]-dp[v][i-2]); dfs2(v,x); } }
Code:
#include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #define pb push_back #define popb pop_back #define fi first #define se second const int N=1e5+10; //const int M=; //const int inf=0x3f3f3f3f; //const ll INF=0x3ffffffffffff; int T,n,k,a[N],dp[N][30],f[N][30]; vector<int> g[N]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } void dfs1(int x,int fa) { dp[x][0]=a[x]; for(auto v:g[x]) { if(v==fa) continue; dfs1(v,x); } for(int i=1;i<=k;i++) { dp[x][i]=a[x]; for(auto v:g[x]) { if(v==fa) continue; dp[x][i]+=dp[v][i-1]; } } } void dfs2(int x,int fa) { if(x==1) for(int i=1;i<=k;i++) f[1][i]=dp[1][i]; for(auto v:g[x]) { if(v==fa) continue; f[v][0]=dp[v][0]; f[v][1]=dp[v][1]+a[x]; for(int i=2;i<=k;i++) f[v][i]=dp[v][i]+(f[x][i-1]-dp[v][i-2]); dfs2(v,x); } } int main() { // freopen("","r",stdin); // freopen("","w",stdout); n=read(),k=read(); for(int i=1;i<n;i++) { int u=read(),v=read(); g[u].pb(v); g[v].pb(u); } for(int i=1;i<=n;i++) a[i]=read(); dfs1(1,0); dfs2(1,0); for(int i=1;i<=n;i++) printf("%d\n",f[i][k]); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通