TYOI Day1 travel:Tree dp【处理重复走边】

题意:

  给你一棵树,n个节点,每条边有长度。

  然后有q组询问(u,k),每次问你:从节点u出发,走到某个节点的距离mod k的最大值。

题解:

  对于无根树上的dp,一般都是先转成以1为根的有根树,然后分别从上到下和从下到上两遍dp。

  另一个技巧是:处理重复走边的情况时,可以让dp值表示达到某种状态的方案数。

  表示状态:

    dp[i][j][k] = max dis

    表示从i节点出发,走的距离mod k = j时的方案数

  找出答案:

    对于每次询问(u,k),答案为:满足dp[u][d][k]>0的最大的d值。

  如何转移:

    第一遍dfs:

      dp[i][(j+len)%k][k] = ∑ dp[son][j][k]

      只考虑从上往下的路径。

    第二遍dfs:

      dp[i][(j+len)%k][k] += dp[par][j][k]

      dp[i][(j+len)%k][k] -= old[i][((j-len)%k+k)%k][k]

      其中old[i][j][k]代表原来的dp,即只考虑从上往下时的dp。

      减去old是因为要将会导致重复走边的方案删去。

  边界条件:

    dp[i][0][k] = 1

    others = 0

  复杂度:

    Tree dp: O(n*k*k)

    Query: O(q*k)

AC Code:

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <vector>
  5 #define MAX_N 3005
  6 #define MAX_K 105
  7
  8 using namespace std;
  9
 10 struct Edge
 11 {
 12     int dst;
 13     int len;
 14     Edge(int _dst,int _len)
 15     {
 16         dst=_dst;
 17         len=_len;
 18     }
 19     Edge(){}
 20 };
 21
 22 int n,q;
 23 int dp[MAX_N][MAX_K][MAX_K];
 24 int old[MAX_N][MAX_K][MAX_K];
 25 vector<Edge> edge[MAX_N];
 26
 27 void read()
 28 {
 29     cin>>n;
 30     int x,y,z;
 31     for(int i=1;i<n;i++)
 32     {
 33         cin>>x>>y>>z;
 34         edge[x].push_back(Edge(y,z));
 35         edge[y].push_back(Edge(x,z));
 36     }
 37 }
 38
 39 void dfs1(int now,int p)
 40 {
 41     for(int i=0;i<edge[now].size();i++)
 42     {
 43         Edge temp=edge[now][i];
 44         if(temp.dst!=p) dfs1(temp.dst,now);
 45     }
 46     for(int k=1;k<=100;k++)
 47     {
 48         for(int i=0;i<edge[now].size();i++)
 49         {
 50             Edge temp=edge[now][i];
 51             if(temp.dst!=p)
 52             {
 53                 for(int j=0;j<k;j++)
 54                 {
 55                     dp[now][(j+temp.len)%k][k]+=dp[temp.dst][j][k];
 56                 }
 57             }
 58         }
 59     }
 60 }
 61
 62 void dfs2(int now,int p,int l)
 63 {
 64     if(p!=-1)
 65     {
 66         for(int k=1;k<=100;k++)
 67         {
 68             for(int j=0;j<k;j++)
 69             {
 70                 old[now][j][k]=dp[now][j][k];
 71             }
 72         }
 73         for(int k=1;k<=100;k++)
 74         {
 75             for(int j=0;j<k;j++)
 76             {
 77                 dp[now][(j+l)%k][k]+=dp[p][j][k];
 78                 dp[now][(j+l)%k][k]-=old[now][((j-l)%k+k)%k][k];
 79             }
 80         }
 81     }
 82     for(int i=0;i<edge[now].size();i++)
 83     {
 84         Edge temp=edge[now][i];
 85         if(temp.dst!=p) dfs2(temp.dst,now,temp.len);
 86     }
 87 }
 88
 89 void work()
 90 {
 91     memset(dp,0,sizeof(dp));
 92     for(int i=1;i<=n;i++)
 93     {
 94         for(int k=1;k<=100;k++)
 95         {
 96             dp[i][0][k]=1;
 97         }
 98     }
 99     dfs1(1,-1);
100     dfs2(1,-1,0);
101     cin>>q;
102     int u,k;
103     while(q--)
104     {
105         cin>>u>>k;
106         for(int d=k-1;d>=0;d--)
107         {
108             if(dp[u][d][k])
109             {
110                 cout<<d<<endl;
111                 break;
112             }
113         }
114     }
115 }
116
117 int main()
118 {
119     read();
120     work();
121 }

原文地址:https://www.cnblogs.com/Leohh/p/8290205.html

时间: 2024-08-11 07:49:50

TYOI Day1 travel:Tree dp【处理重复走边】的相关文章

HDU 4359 Easy Tree DP?

Easy Tree DP? Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1487    Accepted Submission(s): 567 Problem Description A Bear tree is a binary tree with such properties : each node has a value o

hdu5534 Partial Tree dp(难)

hdu5534 Partial Tree  dp(难) Partial Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)Total Submission(s): 374    Accepted Submission(s): 209 Problem Description In mathematics, and more specifically in graph t

HDU 4359——Easy Tree DP?——————【dp+组合计数】

Easy Tree DP? Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 1460    Accepted Submission(s): 557 Problem Description A Bear tree is a binary tree with such properties : each node has a value o

codeforces 514E Darth Vader and Tree (dp+快速幂)

codeforces 514E Darth Vader and Tree (dp+快速幂) 题意: 有一棵树,每个节点有n个儿子,给出父亲到每个儿子的距离di,问离祖先距离不超过x的子孙有多少个(子孙包括祖先)对1e9+7取模. 限制: 1 <= n <= 1e5; 0 <= x <= 1e9; 1 <= di <= 100 思路: 因为di <= 100,所以可以用快速幂来处理这道题, 大概过程为:先用dp算出前100的答案,剩下的用快速幂来处理.

HDU5293(SummerTrainingDay13-B Tree DP + 树状数组 + dfs序)

Tree chain problem Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 1798    Accepted Submission(s): 585 Problem Description Coco has a tree, whose vertices are conveniently labeled by 1,2,-,n.The

HDU3534(SummerTrainingDay13-C tree dp)

Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1574    Accepted Submission(s): 511 Problem Description In the Data structure class of HEU, the teacher asks one problem: How to find the lon

poj 3230 Travel(dp)

Description One traveler travels among cities. He has to pay for this while he can get some incomes. Now there are n cities, and the traveler has m days for traveling. Everyday he may go to another city or stay there and pay some money. When he come

bzoj 1017 tree dp

这道题几经波折啊. 最开始和vfleaking一样,把题意理解错了,认为一个装备可能被多个装备依赖,然后想不出来,去看题解. 发现自己理解错了题意,自己想想,其实也不难想到dp[i][j][k]表示“i号节点代表的子树,用掉j的钱,给父亲预留k个自己(但还是父亲付钱)”的状态,写出来交上去就是T, 开始以为是常数问题,优化半天还是T,看了他人AC代码,才发现自己算法有一定问题:重复计算了很多东西. 树形动规,一般在大的树规下,每个节点还会对儿子们来一次”资源分配“,一般是用背包解决,这道题也是这

DP Intro - Tree DP Examples

因为上次比赛sb地把一道树形dp当费用流做了,受了点刺激,用一天时间稍微搞一下树形DP,今后再好好搞一下) 基于背包原理的树形DP poj 1947 Rebuilding Roads 题意:给你一棵树,让你求最少剪掉多少条边可以剪出一棵点数为m的子树. 解法:dp[i][j]表示i节点得到j个节点的子树至少要剪多少边,对于每个节点a和它的孩子b,如果剪掉b,则dp(s)[a][j]=dp(s-1)[a][j], 如果保留<a,b>dp(s)[a][j]=min{dp(s-1)[a][j - k