一、题目描述:
给你一棵 n 个点的树,点带权,对于每个节点,求出距离它不超过 k 的所有节点权值和。n<=1e5,k<=20。
二、解题思路:
这题一开始想了一个 O(knlogn) 的线段树合并,写了一半感觉不好转移,最后写了十几分钟的 dp 写出来了。( dp代码就是短 )
两遍 dfs 。第一遍统计从儿子到父亲,第二遍统计从父亲到儿子,注意一些细节即可,不多讲。时间复杂度 O(kn)。
三 、完整代码:
1 #include<iostream> 2 #include<cstring> 3 #define N 100010 4 using namespace std; 5 int n,k,u1,v1; 6 int c[N],ans[N],f[N][25]; 7 struct EDGE{ 8 int v,nxt; 9 }edge[N*2]; 10 int head[N],cnt; 11 void add(int u,int v) 12 { 13 edge[++cnt].v=v; 14 edge[cnt].nxt=head[u]; 15 head[u]=cnt; 16 } 17 void dfs1(int now,int ff) 18 { 19 f[now][0]+=c[now]; 20 for(int i=head[now];i!=-1;i=edge[i].nxt) 21 if(edge[i].v!=ff) 22 { 23 dfs1(edge[i].v,now); 24 for(int j=1;j<=k;j++) 25 f[now][j]+=f[edge[i].v][j-1]; 26 } 27 } 28 void dfs2(int now,int ff) 29 { 30 for(int i=head[now];i!=-1;i=edge[i].nxt) 31 if(edge[i].v!=ff) 32 { 33 for(int j=k;j>=2;j--) 34 f[edge[i].v][j]-=f[edge[i].v][j-2]; 35 //这里注意倒序枚举 36 for(int j=2;j<=k;j++) 37 f[edge[i].v][j]+=f[now][j-1]; 38 f[edge[i].v][1]+=c[now]; 39 dfs2(edge[i].v,now); 40 } 41 } 42 int main() 43 { 44 ios::sync_with_stdio(false); 45 cin.tie(0);cout.tie(0); 46 cin>>n>>k; 47 memset(head,-1,sizeof(head)); 48 for(int i=1;i<n;i++) 49 { 50 cin>>u1>>v1; 51 add(u1,v1),add(v1,u1); 52 } 53 for(int i=1;i<=n;i++) 54 cin>>c[i]; 55 dfs1(1,0);dfs2(1,0); 56 for(int i=1;i<=n;i++) 57 for(int j=0;j<=k;j++) 58 ans[i]+=f[i][j]; 59 for(int i=1;i<=n;i++) 60 cout<<ans[i]<<'\n'; 61 return 0; 62 }
四、做题心得:
感觉这题真没啥难度,不过做了一道蓝题还是挺高兴的啦。拜拜!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】