一、题目描述:
给你一棵 n 个点的树,点带权,对于每个节点,求出距离它不超过 k 的所有节点权值和。
二、做题思路:
这题一开始想了一个 O(knlogn) 的线段树合并,写了一半感觉不好转移,最后写了十几分钟的 dp 写出来了。( dp代码就是短 )
两遍 dfs 。第一遍统计从儿子到父亲,第二遍统计从父亲到儿子,注意一些细节即可,不多讲。
三、完整代码:
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 for(int j=2;j<=k;j++) 36 f[edge[i].v][j]+=f[now][j-1]; 37 f[edge[i].v][1]+=c[now]; 38 dfs2(edge[i].v,now); 39 } 40 } 41 int main() 42 { 43 ios::sync_with_stdio(false); 44 cin.tie(0);cout.tie(0); 45 cin>>n>>k; 46 memset(head,-1,sizeof(head)); 47 for(int i=1;i<n;i++) 48 { 49 cin>>u1>>v1; 50 add(u1,v1),add(v1,u1); 51 } 52 for(int i=1;i<=n;i++) 53 cin>>c[i]; 54 dfs1(1,0);dfs2(1,0); 55 for(int i=1;i<=n;i++) 56 for(int j=0;j<=k;j++) 57 ans[i]+=f[i][j]; 58 for(int i=1;i<=n;i++) 59 cout<<ans[i]<<'\n'; 60 return 0; 61 }
四、做题心得:
感觉这题真没啥难度,不过做了一道蓝题还是挺高兴的啦。拜拜!