【换根DP】生活在树上

谁践踏了优雅 2024-03-16 20:09 210阅读 0赞

换根DP板子题

D-生活在树上_牛客小白月赛46 (nowcoder.com)

题意:

f9fe948c869e4fd083aaee11113cd7c7.png

思路:

看数据范围是1e6且是统计问题,求的是对于每一个点的统计问题,那就逃不出是换根DP了

首先dfs1一次把树形DP求出来,然后再考虑换根

设dp[u][j]为以u为根的子树中,离根u的距离是j的结点个数

这个很容易转移,但是注意要对边权分类讨论

然后考虑换根,换根的时候注意是从上到下更新dp数组

是根据u结点的dp值和v的dp值更新儿子结点的dp2值,即dp2[v]=…dp[u]+….的形式

3fd14b2e829f43a4bec14d60520e464c.jpeg

Code:

  1. #include <bits/stdc++.h>
  2. #define int long long
  3. using namespace std;
  4. using i64 = long long;
  5. const int mxn=1e6+10;
  6. const int mxe=1e6+10;
  7. const int mod=1e9+7;
  8. struct ty{
  9. int to,next,w;
  10. }edge[mxe<<2];
  11. int N,Fa,d,tot=0;
  12. int head[mxn],dp[mxn][3];
  13. void add(int u,int v,int w){
  14. edge[tot].w=w;
  15. edge[tot].to=v;
  16. edge[tot].next=head[u];
  17. head[u]=tot++;
  18. }
  19. void G_init(){
  20. tot=0;
  21. for(int i=0;i<=N;i++){
  22. head[i]=-1;
  23. }
  24. }
  25. void dfs1(int u,int fa){
  26. dp[u][0]=1;
  27. dp[u][1]=dp[u][2]=0;
  28. for(int i=head[u];~i;i=edge[i].next){
  29. if(edge[i].to==fa) continue;
  30. dfs1(edge[i].to,u);
  31. if(edge[i].w==1){
  32. dp[u][1]+=dp[edge[i].to][0];
  33. dp[u][2]+=dp[edge[i].to][1];
  34. }else if(edge[i].w==2){
  35. dp[u][1]+=0;
  36. dp[u][2]+=dp[edge[i].to][0];
  37. }
  38. }
  39. }
  40. void dfs2(int u,int fa){
  41. for(int i=head[u];~i;i=edge[i].next){
  42. if(edge[i].to==fa) continue;
  43. if(edge[i].w==1){
  44. dp[edge[i].to][1]+=dp[u][0];
  45. dp[edge[i].to][2]+=dp[u][1]-1;
  46. }else if(edge[i].w==2){
  47. dp[edge[i].to][2]+=dp[u][0];
  48. }
  49. dfs2(edge[i].to,u);
  50. }
  51. }
  52. void solve(){
  53. cin>>N;
  54. G_init();
  55. for(int i=2;i<=N;i++){
  56. cin>>Fa>>d;
  57. add(i,Fa,d);
  58. add(Fa,i,d);
  59. }
  60. dfs1(1,-1);
  61. dfs2(1,-1);
  62. for(int i=1;i<=N;i++) cout<<dp[i][0]+dp[i][1]+dp[i][2]<<'\n';
  63. }
  64. signed main(){
  65. ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
  66. int __=1;//cin>>__;
  67. while(__--)solve();return 0;
  68. }

但是注意dfs2不能写成如下形式:

  1. void dfs2(int u,int fa){
  2. dp2[u][0]=1;
  3. for(int i=head[u];~i;i=edge[i].next){
  4. if(edge[i].to==fa) continue;
  5. if(edge[i].w==1){
  6. dp2[edge[i].to][1]=dp[edge[i].to][1]+dp[u][0];
  7. dp2[edge[i].to][2]=dp[edge[i].to][2]+dp[u][1]-1;
  8. }else if(edge[i].w==2){
  9. dp2[edge[i].to][1]=dp[edge[i].to][1];
  10. dp2[edge[i].to][2]=dp[edge[i].to][2]+dp[u][0];
  11. }
  12. dfs2(edge[i].to,u);
  13. }
  14. }

因为父节点被不断更新,这里加上的应该是被更新过的父节点的dp值!

所以在写换根DP的时候,不能另开一个数组,而是累加

发表评论

表情:
评论列表 (有 0 条评论,210人围观)

还没有评论,来说两句吧...

相关阅读