HDU 5593 ZYB's Tree 树形dp

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5593

题意:

http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=654&pid=1004

题解:

先自底向上跑一遍,求出以u为根的子树中与u距离小于等于k的节点数(不同的距离要分开存,否则无法递推上去,dp[u][i]存距离为i的节点数)

求好之后,再dfs一遍,这次换做自顶向下,目的是求u的兄弟(和兄弟的后代)以及u的祖先(和祖先的后代,不包括以u为根的子树)中与u距离小于等于k的节点数(也是分开存)

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int maxn=5e5+10;
 8 typedef long long LL;
 9 
10 int dp[maxn][11];
11 int fa[maxn];
12 int N,K,A,B;
13 
14 struct Edge{
15     int v,ne;
16     Edge(int v,int ne):v(v),ne(ne){}
17     Edge(){}
18 }egs[maxn*2];
19 
20 int head[maxn],tot;
21 
22 void addEdge(int u,int v){
23     egs[tot]=Edge(v,head[u]);
24     head[u]=tot++;
25 }
26 //从下往上跑一遍 
27 void dfs1(int u){
28     int p=head[u];
29     while(p!=-1){
30         Edge& e=egs[p];
31         dfs1(e.v);
32         for(int i=1;i<=K;i++){
33             //转移方程1: 
34             dp[u][i]+=dp[e.v][i-1];
35         }
36         p=e.ne;
37     }
38     dp[u][0]=1;
39 }
40 //从上往下跑一遍 
41 void dfs2(int u){
42     if(fa[u]){
43         for(int i=K;i>=2;i--){
44             //转移方程2: 
45             dp[u][i]+=dp[fa[u]][i-1]-dp[u][i-2];//dp[fa[u]][i-1]有包括u本身,所以要扣掉u的那部分对fa[u]的贡献 
46         }
47         dp[u][1]++;
48     }
49     int p=head[u];
50     while(p!=-1){
51         Edge& e=egs[p];
52         dfs2(e.v);
53         p=e.ne;
54     }
55 }
56 
57 void init(){
58     fa[1]=0;
59     memset(dp,0,sizeof(dp));
60     memset(head,-1,sizeof(head));
61     tot=0;
62 }
63 
64 int main(){
65     int tc;
66     scanf("%d",&tc);
67     while(tc--){
68         scanf("%d%d%d%d",&N,&K,&A,&B);
69         init();
70         for(int i=2;i<=N;i++){
71             int x=((LL)A*i+B)%(i-1)+1;
72             addEdge(x,i);
73             fa[i]=x;
74         }
75         dfs1(1);
76         dfs2(1);
77         LL ans=0;
78         for(int i=1;i<=N;i++){
79             int cnt=0;
80             for(int j=0;j<=K;j++) cnt+=dp[i][j];
81             ans^=cnt;
82         }
83         printf("%lld
",ans);
84     }
85     return 0;
86 }